xman_2019_format
总结
根据本题,学习与收获有:
printf
的字符串,如果是在堆上,那么就无法在栈上写地址利用%x$hn
去修改printf
会一次性取出所有的偏移的地址,再去修改。不是边写边修改!(结合调试过程理解!)- 由于
ebp
寄存器会记录一个栈地址链,所以可以利用这一点特性,爆破修改这个栈地址链的最低字节,然后修改ebp
寄存器后4
个字节的内容,理想状态下,爆破1
个字节即可,而且,所有的地址都是对齐到地址页。
题目分析
checksec
函数分析
main
sub_804869D
sub_8048651
sub_804862A
sub_80485c4
层层套娃,终于走到了最后的处理函数。strtok
是字符串分割函数,分割的符号为|
。
漏洞点
漏洞点很清楚,就是函数sub_80485c4
中,将传入的字符串使用|
分割后,直接调用printf
函数。很明显的格式化字符串漏洞。但是这里要注意:字符串存储在堆上。所以,不能在栈上写地址,然后利用栈的偏移来向任意地址写。因此,只能借助栈上已有的地址,往eip
寄存器里面写入目标地址。
注意到有一个后门函数:
只需要覆盖为这个函数的地址即可。
利用思路
因此,本题利用的思路很清晰:
-
printf
确定偏移 -
利用栈上的地址链,特别是
ebp
地址链,修改中间某一个地址的最低字节,修改为存储eip
寄存器内容的那个地址 -
将这个可能会被压入
eip
寄存器的地址的内容,修改为0x80475AB
-
get_shell
EXP
调试过程
本题需要一步步调试出来,首先测试一下偏移:
|
|
输入之前看一下栈:
这个调用链还是很明显的
执行完成打印出来的内容为:
数一下,偏移为10
。
这个时候需要结合栈图整理一下思路:
- 首先修改
0xffffceb8
地址处的内容为0xffffce9c
,这里需要修改最低的一个字节,偏移为10 - 然后修改
0xffffce9c
地址处的内容为0x80485ab
,这里只需要修改最低的两个字节,偏移为18
很容易写出最后的输入应该为:
%156c%10$hhn%34219c%18$hn
可以调试一下,在printf
函数下个断点,然后观察一下0xfffceb8
的内容变化:
第一次命中断点:
第二次命中断点:
此处的值已经改变:
可以看到,最低字节已经修改成功。然后继续执行printf
,看下0xffffce9c
是不是修改为目标值:
发现修改失败了:
还是修改的最初的0xffffcee8
的内容,并不是去修改的0xffffce9c
的内容!这说明,printf
格式化执行的时候,首先把所有对应偏移的地址先取出来,然后再去修改!
题目中,有一个|
分割符,因此,只需要利用分割符分开输入即可!
所以,最终的输入为:
%156c%10$hhn|%34219c%18$hn
执行了/bin/bash
完整exp
实际上需要爆破最低的那个字节,所以最终的exp如下:
|
|
远程爆破过程为: