import gmpy2 n = 29331922499794985782735976045591164936683059380558950386560160105740343201513369939006307531165922708949619162698623675349030430859547825708994708321803705309459438099340427770580064400911431856656901982789948285309956111848686906152664473350940486507451771223435835260168971210087470894448460745593956840586530527915802541450092946574694809584880896601317519794442862977471129319781313161842056501715040555964011899589002863730868679527184420789010551475067862907739054966183120621407246398518098981106431219207697870293412176440482900183550467375190239898455201170831410460483829448603477361305838743852756938687673 c = 2205316413931134031074603746928247799030155221252519872649649212867614751848436763801274360463406171277838056821437115883619169702963504606017565783537203207707757768473109845162808575425972525116337319108047893250549462147185741761825125
for k inrange(100000): [r, exact] = gmpy2.iroot(c+n*k, 3) if exact: print(k) print(bytes.fromhex(hex(r)[2:]))
因為數字很大的緣故所以沒辦法用 pow 來驗證是不是整數的三次方,就用了
gmpy2
另一個方法是用 RsaCtfTool 的 cube_root
Attack,它用了二分搜
b00tl3gRSA2
我們得到的 e 很大,但實際應用上來說 e 並不大,所以那個 e 實際上大概是
d。
再來 RSA 就數學上來說用 e 或 d 來加密是沒有差的,不過因為 e 和 d
一般都有一定的大小差距,所以有些特殊的方法可以在特定情況下幫你破解
RSA。像是 Google 搜尋一下 RSA small d 就告訴我們有個 Wiener's
attack 可以應用在這種情況下。
chs = list('jU5t_a_sna_3lpm18g947_u_4_m9r54f') for i inrange(0, 8): s.add(p[i] == ord(chs[i])) for i inrange(8, 16): s.add(p[i] == ord(chs[23-i])) for i inrange(16, 32, 2): s.add(p[i] == ord(chs[46-i])) for i inrange(31, 16, -2): s.add(p[i] == ord(chs[i]))
if s.check() == sat: print(s.model()) else: print(s.unsat_core())
vault-door-4
想辦法把它的各種格式轉換一下就好了,像是轉成 python 能接受的 input
直接貼進去。
vault-door-5
Base64 + URL encoding
vault-door-6
丟進 python 做 xor
vault-door-7
簡單的 Shifting:
1 2 3 4 5 6 7
x = [1096770097, 1952395366, 1600270708, 1601398833, 1716808014, 1734304867, 942695730, 942748212]
flag = b'' for y in x: flag += bytes.fromhex(hex(y)[2:]) print(flag)
x = [ord(c)-97for c in"lfmhjmnahapkechbanheabbfjladhbplbnfaijdajpnljecghmoafbljlaamhpaheonlmnpmaddhngbgbhobgnofjgeaomadbidl"] key = String('key') s = Solver() s.add(Length(key) == len(x))
assert(s.check() == sat) m = s.model() key = m[key].as_string() print(key) k = int(key, 16) flag = int( "a5d47ae6ffa911de9d2b1b7611c47a1c43202a32f0042246f822c82345328becd5b8ec4118660f9b8cdc98bd1a41141943a9", 16) flag ^= k print(''.join([chr(c) for c inbytes.fromhex(hex(flag)[2::])]))
reverse_cipher
一樣是 z3 下去解決:
1 2 3 4 5 6 7 8 9 10 11 12 13
from z3 import *
target = [ord(c) for c in"w1{1wq84fb<1>49"] key = String('key') s = Solver()
s.add(Length(key) == len(target)) for i inrange(len(target)): c = key[i] s.add(If(i & 1 != 0, c-2, c+5) == target[i])
withopen(sys.argv[1], 'r') as f: lines = f.readlines()
prog = '' lst_lbl = None for line in lines[1:]: line = re.sub(r'<\+(\d+)>', r'L\1', line) line = re.sub(r'0x.*?<.*?\+(\d+)>', r'L\1', line) prog += line lbl = re.search(r'L\d+', line) if lbl: lsl_lbl = lbl[0]
withopen(asm_file, 'r') as f: lines = f.readlines()
prog = '' lst_lbl = None for line in lines: line = re.sub(r'<\+(\d+)>:', r'', line) line = re.sub(r'0x.*?<(.*?\+\d+)>', r'\1', line) prog += line lbl = re.search(r'L\d+', line) if lbl: lsl_lbl = lbl[0]
s = Solver() arr = Array('arr', IntSort(), IntSort()) for i inrange(len(data)): s.add(arr[i] == data[i]) # arr = Store(arr, i, data[i]) is very slow shifters = [Int(f's_{i}') for i inrange(16)] for x in shifters: s.add(0 <= x) s.add(x <= 9) result = [0]*len(data) for i inrange(16): shifter = shifters[i] for j inrange(len(data)//16): result[(j*16)+i] = arr[(((j+shifter)*16) % len(data))+i]
while s.check() == sat: m = s.model() shs = [m[x].as_long() for x in shifters] result=[0]*len(data) for i inrange(16): sh=shs[i] for j inrange(len(data)//16): result[(j*16)+i] = data[(((j+sh)*16) % len(data))+i] if'IEND'in''.join([chr(c) for c in result]): # Checks for IEND as there are multiple satisifying solutions print(''.join([str(s) for s in shs])) s.add(reduce(Or, [x != m[x].as_long() for x in shifters]))
s = Solver() arr = Array('arr', IntSort(), IntSort()) for i inrange(len(data)): s.add(arr[i] == data[i]) # arr = Store(arr, i, data[i]) is very slow shifters = [Int(f's_{i}') for i inrange(16)] for x in shifters: s.add(0 <= x) s.add(x <= 9) result = [0]*len(data) for i inrange(16): shifter = shifters[i] for j inrange(len(data)//16): result[(j*16)+i] = arr[(((j+shifter)*16) % len(data))+i]
while s.check() == sat: m = s.model() shs = [m[x].as_long() for x in shifters] result = [0]*len(data) for i inrange(16): sh = shs[i] for j inrange(len(data)//16): result[(j*16)+i] = data[(((j+sh)*16) % len(data))+i] if''.join([chr(c) for c in [0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]]) in''.join([chr(c) for c in result]): # Full IEND print(''.join([str(s)+'0'for s in shs])) s.add(reduce(Or, [x != m[x].as_long() for x in shifters]))
> /usr/bin/checksec --file=vuln RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH 1844) Symbols No 0 0 vuln
p = remote('jupiter.challenges.picoctf.org', 51462) # process('./vuln') whileTrue: line = p.readline() ifb"like to guess"in line: p.sendline("2") elifb"Congrats"in line: p.sendline(payload) break p.interactive()
Guessing Game 2
首先一樣是要你猜數字,只是注意到 get_random
裡面回傳的是函數 rand 的位置,所以用 gdb
理論上是可以弄到的,但因為是在對方的 server 上執行,libc
的版本應該都是不同的,所以只能暴力找:
1 2 3 4 5 6 7 8
from pwn import * p = remote('jupiter.challenges.picoctf.org', 13775) for i inrange(-4100, 4100): # Note: -5 % 3 == -1 in C p.recvuntil('What number') p.sendline(str(i)) ifb'Congrats'in p.recvline(): print(i) break
給不想花時間在這上面的人,答案是 -31
再來是到 win() 函數,有明顯的 buffer overflow 和 format
string 兩個問題,所以先來做些檢查看看要用什麼方法。checksec
告訴你有 NX, Canary, RELRO,只有 PIE 沒有,然後再用 ROPgadget
看一下有沒有 syscall 或是
int 0x80,只是也找不到,最後找找看 /bin/sh 的
string 也是沒有,所以大概只剩下 return to libc 能用了。
不過它沒有提供給我們 libc,所以只能想辦法找,就先在 local 這邊用 gdb
找一下各個重要 address 和 format string 的 offset 是多少,然後再用 LibcSearcher 去找 libc
版本,然後就能很方便的算出 address 了。