티스토리 뷰

CTF write-up

Samsung CTF (SCTF) 2018 catch_the_bug

marshimaro aSiagaming 2018. 7. 8. 10:55


원본 바이너리에 sleep이 짜쯩나서 로컬에서 푸는 것에서는 패치시키고 진행하였다. ( 익스에 지장 없음 )
이 문제는 약간의 brute forcing이 필요하기도한데, 왜냐하면 catch() 함수에서 곤충을 채집할 때, rand(time(0))값 기반으로 랜덤하게 잡히기 떄문이고, overflow를 유발시켜서 공격을 할려면 나비를 무조건 한 마리 잡아야하기 때문이다.

릭은 format string버그가 있어서 딱 라이브러리 영역 주소만 알아낼 수 있으며, PIE, RELRO 옵션이기때문에, 라이브러리 영역에서 해결해야 한다.



ReportCursor에는 DestPoint의 Address가 저장되어 있는데, DestPoint와 ReportCursor간의 offset은 1800이다.
그래서 offset을 중간 저 루프문에서 1800이상이 넘어가게되면, ReportCursor의 변수를 덮게 된다.

1 : 0x1fe
2 : 0x1b8
3 : 0x1c0

정확하진 않은 것 같은데 대충 저러함.
적당히 디버깅하면서 length는 맞춰가면 된다.
최종적으로 취약점 자체는, 저 부분 아래에서 입력을 3번 받는데, 0x100만큼 받는 부분에서 그 아래의 2부분 입력받는 주소를 임의로 overwrite할 수 있게 되어, 임의 쓰기 취약점이 발생한다.

근데, 라이브러리 영역에서 모든걸 해결해야하는 상황이고, malloc/free또한 후에 눈에 띄게 사용되지는 않는다.
처음에 떠올렷던 것은, __tls_get_addr@got인데, exit() 함수의 직접적인 호출에 의하면, 해당 루틴을 타는 것으로 알고 있는데, return이후 __libc_start_main으로 정상종료하기 떄문에, 저 부분을 덮는 것은 크게 의미가 없었다.

이것저것 검색해보던 와중 아래와 같은 것으 발견할 수 있었다.



일종의, exit에 대한 atexit류의 핸들러와도 같은데 라이브러리 initial이라는 영역에 핸들러에 대한 값을 가지게 된다.



대략적인 구조는 위와 같으며, idx만큼 flavor(command)에 대한 루프를 돌며, 이에 맞춰 함수를 호출하는 역할을 한다.
하지만, libc-2.26이상 버전에서는 PTR_DEMANGLE이라는 매크로가 추가되어, 로더부분의 xor 키 값을 알아내는 것 아니고는 함수부분을 임의로 overwrite하여 사용할 수 없다.



위와 같이 ror연산 이후, fs:0x30에서 가져온 값과 xor하는데, 저걸 알아낼 방법이 여기서는 존재하지 않는다.



일단 해당 부분의 소스코드는 위와 같은데, 저기서는 별 볼 일 없고 아래의 부분이 솔루션의 핵심이다.



listp는 루프문을 빠져나온 이후, cur->next(첫 멤버)를 통해 새롭게 갱신하게되는데, next값이 존재할 경우, 기존의 cur를 free시킨다.
2번의 오버라이트가 존재하기때문에, 저 조건을 이용하여 next멤버를 조절해주고, __free_hook을 원샷가젯으로 덮어주면, 쉘을 획득할 수 있게 된다.