ipwn
[CODEGATE 2015] yocto (RTDL) 본문
rtdl 정리할 겸 yocto 라업 써야겠다.
갑자기 든 생각인데 왜 티스토리는 md를 지원 안할까... 컬러스크립트 쓰기 싫은데.. 좀 공부하고 github.io로 갈아타야지
무튼 라업 읽기전에 읽어야 할 문서 2개 땅땅 (got에 왜 libc 주소가 있을까요~~?~를 알자)
https://bpsecblog.wordpress.com/2016/03/07/about_got_plt_1/
https://bpsecblog.wordpress.com/2016/03/09/about_got_plt_2/
굳
Mitigation
|
아 진짜 보기 싫게 생겼다...
무튼 렐로도 없고 파이도 없고 카나리도 없다. 오직 NX만 존재함
Analysis
|
main도 없이 바로 _start에서 할 거 다 한다.
취약점을 찾을게 아니라 이건 공부하라고 준 binary다.
그래도 분석을 하자.
0. fd들을 닫는다.
1. glob라는 전역변수에 read로 입력을 0x50만큼 받는다.
2. . 으로 구분해서 glob에 입력받은 string을 atoi함수에 넣는다.
3. 2에서 진행된 atoi함수의 return값을 스택에 박아넣는다.
4. 마지막 atoi함수 return값은 eip로 사용 된다.
eip를 대놓고 돌릴 수 있지만 NX도 걸려있어서 할 수 있는게 없어보인다.
사실 있다. RTDL 하면 된다.
RTDL을 공부하기 위해서는 plt와 got가 어떻게 동작하는지 알아야한다.
setvbuf를 기준으로 따라가보자...(위에 링크건 곳에도 있지만 내가 공부하려고 한 번 더 정리함.)
|
위는 gdb로 메모리를 까본 것이다.
같은 글자, 배경 색으로 분류 해놓은 것인데.. 어째 더 번잡해진듯..
간단하게 정리를 해보겠다.
setvbuf@plt -> *setvbuf@got(setvbuf@plt + 6) -> push 0x10(reloc_offset) -> jmp 0x80482a0(Dynamic Linking의 시작)
push *0x8049534(Link_map struct pointer) -> jmp *0x8049538(_dl_runtime_resolve)
위의 절차를 거치게 된다.
plt와 got를 잘 쫓아가고 _dl_runtime_resolve -> _dl_fixup을 잘 따라가서 어셈블리를 보면 JMPREL과 STRTAB의 주소를 구할 수 있다.
아마도 위에 링크 걸어 둔 거랑 어셈블리가 다를텐데 잘 찾아보면 비슷한 게 있다. 바로 그거다.
(위에 링크는 어셈블리에서 STRTAB를 먼저 다루고 JMPREL을 다뤘는데 내 환경에서는 JMPREL을 먼저 다루고 STRTAB를 다뤘다.)
JMPREL
|
STRTAB
|
JMPREL = 0x08048270
STRTAB = 0x080481fc
JMPREL은 8byte의 Elf32_rel구조체로 이뤄져 있는데 첫 4byte는 함수의 got, 2번째 4byte의 첫 1byte는 재배치 방식이고 나머지는 DYNSYM의 index를 의미한다.
그리고나서 보면 setvbuf의 reloc_offset은 0x10이므로 JMPREL + 0x10에 setvbuf의 got, DYNSYM index, 재배치 방식이 담겨져있다.
(0x8048280: 0x08049544 0x00000307 << 요거 말하는 거)
DYNSYM는 동적 심볼 테이블로 import하거나 export하는 심볼들이 담겨있으며 16byte의(4byte 3개, 1byte 2개, 2byte 1개) Elf32_sym의 구조체로 이뤄져있다.
DYNSYM
|
여기서 필요한 값은 맨 처음 4byte의 값과 구조체의 5번째 값. 헷갈릴까봐 볼드체로 두껍게 해놓고 색깔까지 바꿔놓은 저 부분들만 중요하게 보면 된다.
빨갛게 색칠된 저 값들은 STRTAB에서부터 함수의 string까지의 offset을 의미한다.
|
setvbuf의 DYNSYM index인 3번째 index에 존재하는 offset(0x2c)을 STRTAB에 더해주었더니 setvbuf라는 string이 존재하는 것을 확인할 수 있다.
그리고 파랗게 색칠 된 저 부분은 이미 함수가 Loading이 되었는지 아닌지를 판단해준다.
만약 저 부분의 값을 3과 & 연산을 했을 때 0이 아닌 다른 값이 나온다면 이미 Loading이 되었다고 판단, 바로 호출해버린다.
어쨌든 이런 일련의 과정을 거쳐서 eax에 함수의 string을 담은 후, _dl_lookup_symbol_x라는 함수를 호출해준다.
|
그런데 이 함수는 분석하기에는 양이 굉장히 방대하다.
그래서 ni로 한 줄 진행시킨 후의 register나 stack의 변화 상태를 보겠다.
|
함수 실행 직후에는 eax에 libc의 시작 주소의 포인터가 담겨져있고, esp + 0x28에는 SYMTAB의 주소가 담겨져있다.
(SYMTAB에는 여러가지 offset값이 적혀있다.)
그 뒤에 일련의 작업을 거친 후 SYMTAB에서도 우리가 호출할 함수의 offset값만 뽑아와서 got에 libc의 주소를 담게된다.
|
이렇게 함수를 잘 구해왔다.
여기서 의문점 하나가 생긴다.
과연 _dl_lookup_symbol_x 함수의 인자로 우리가 호출하고자 하는 함수의 이름을 넘겨주면 어떻게 될까?
이론상으로라면 그 어떤 함수라도 호출할 수 있을 것이다.
이러한 생각을 가지고 exploit을 작성을 해보자.
익스플로잇 스크립트를 올려놓을테니 만약 이 블로그를 보게되시는 분이 계신다면 직접 디버깅하면서 분석해보시기를 추천합니다.
|
fake 구조체들을 만들어주고 atoi함수의 return값이 stack에 쌓인다는 점을 이용해서 fake reloc_offset을 넣어준 다음 dl_linker로 eip를 돌려주면 인자도 딱딱 맞아 떨어져서 system(v0);의 형태로 함수가 실행된다.
얼마만의 라업인건지 ㅋ.ㅋ
처음에는 fake elf32_rel구조체랑 fake_dynsym구조체 뒤에 system string을 놓아주고 했었는데 왜인지 자꾸 안됐다.
그래서 디버깅 해보니까 스택에 이상한 값 쌓여서 꼬인듯 보여서 system string의 위치를 바꿔주니까 잘 됐다.
재밌었다.
'CTF's > CODEGATE' 카테고리의 다른 글
[CODEGATE 2019] aeiou (0) | 2019.03.17 |
---|---|
[CODAGATE 2018] heapbabe (0) | 2018.11.13 |
[CODEGATE 2018] catshop (0) | 2018.05.17 |
[CODEGATE 2018] betting (0) | 2018.05.17 |
[CODEGATE 2016] bugbug (0) | 2018.03.26 |