1.思考自己能够做什么->使用手写汇编,gcc,objdump的简单组合得到了指令的机器码
2.如何让自己处于一种思维活跃的状态
如何使用ret指令?需要将返回地址压回栈中,第一个想到的是使用覆盖的方法,想去寻找上一级调用的地址,但是没有找到
参考了别人的方法,用了pushq,这种方法是抓住了本质:ret的本质就是把栈指针上方的地址加载
3.注意写汇编代码的时候mov 0x...,%edi错误!立即数应该用 mov $0x...,%edi,对于pushq $0x...也同理!否则产生的机器码是错误的!
level 3,要注意不同函数调用的时候pushq也可能会擦除自己注入的代码,如果在栈的开始就写入,会发现空间根本不够,这该怎么办呢?
我们可以转换思路,在返回地址的后方写入代码,目前个人的猜测是金丝雀值在较后方的位置,给自己留足了空间。
另外在注入代码的时候一般也优先将固定的先写上
ps:gdb中 shell ...或者 !...可以执行命令行的命令
set disassemble-next-line可以显示下一条汇编代码而不是c代码
还有一个需要搞懂的问题,就是在函数调用的过程中栈究竟是如何分配的?自己在返回地址后方继续写入代码为什么没有擦除某些重要的东西?这一部分为什么是空的?
level4,根据提示,自己设想自己能够做什么,推理出这种技术的基本使用方法。注意体会这种技术的思想,非常聪明!
自己能够操控的是第一次跳转的地址,但是无法指定下一次的攻击代码所在地方。
如果要从farm.o中找到cookie:0x59b997fa显然不太可能,而“碰巧配凑”更是不用提,这时候就要想有没有什么自己能够操控的东西,忽然想到了pop指令可以精准地将栈中的值弹入寄存器!首先想到的是弹入%rdi,但是搜索后发现没有,不妨转换思路:先弹入%rax,再用mov %rax,%rdi,搜索后发现符合条件,至此已经成功了一大半!
在实际操作中还犯了一点小错误,就是把farm.o中的地址0x17等等写入自己的十六进制文件中,忽视了在rtarget中函数的位置和farm.o中并不同,需要重新寻找
在这次任务中,对栈有了更深入的理解,前几题中的“返回地址”并不是一个特定的区域,而是就取出栈指针的上方那个值,在getbuf中sub %rsp,0x28,使栈指针减少40,等getbuf返回前又加了回来,栈指针恢复,所以输入的41~48字节可以覆盖返回地址。
level5,更加具有挑战性,关键是在已经有的部分中找一些能够利用的指令。
栈随机化使得自己不能在执行前确认栈的位置,但是自己需要传递一个字符串的地址,自然想到mov %rsp,R,将数据写在最后的位置。但是如何表示%rsp+k来指向这个字符串呢?其中最为重要的是注意到add_xy这个函数,这使得这一攻击构想成为现实。
在实际操作的过程中,要灵活使用多种指令来达到目的,适当利用栈来存储数据,结合 pop使用。因为add_xy使用的两个寄存器是%rdi和%rsi,所以可以将movq目的是%rdi或者%rsi的机器码试验性地搜索,注意如果一条路径没办法实现,还可以试着在中间加入一些中转站,比如movq,%rax,%rdi如果没有的化,有可能movq %rax,%rdx 和movq %rdx,%rdi存在。另外,如果数据的长度比较短,还可以试着搜索movl等更加低级的指令。(联想:而如果数据非常长,可以多次运输==传输)
自己对栈指针的变化一定要非常清楚,比如在ret指令之后栈指针会自动+8,务必注意mov %rsp,R的时候%rsp的值是什么。
另外,我个人的方案并未仅仅在farm.o中寻找gadget,而是在整个rtarget中寻找,多了很多选择。