from pwn import * import ast import random from math import gcd from Crypto.Util.number import bytes_to_long, long_to_bytes from server import PRNG, Card, card_str_to_Card, determine_winner import tqdm def sim_round(deck, rng, phi, computer_e, computer_d): deck = shuffle(rng, deck) print("local hacks 1", rng.seed, rng.index, rng.state) while computer_e < 2 or computer_d < 1: e_array = [] for _ in range(6): e_array.append(str(rng.getnum())) computer_e = int(''.join(e_array)) if gcd(computer_e, phi) == 1: computer_d = pow(computer_e,-1,phi) return computer_e, computer_d, deck def shuffle(rng, deck): new_deck = [] for i in range(len(deck)): x = rng.getnum() if deck[x] not in new_deck: new_deck.append(deck[x]) elif deck[i] not in new_deck: new_deck.append(deck[i]) else: for card in deck: if card not in new_deck: new_deck.append(card) break return new_deck def exploit(): deck = [] deck_str = [] for suit in ["Spades", "Hearts", "Diamonds", "Clubs"]: for i in range(16): deck.append(Card(suit, i)) deck_str.append(str(deck[-1])) deck_str = set(deck_str) server_deck = list(deck) # r = process(["python3", "server.py"]) r = remote("crypto.csaw.io", 5001) r.recvuntil(b"Here are") r.recvuntil(b"--> ") p, q = r.recvline().decode().strip().split(", ") p = int(p) q = int(q) phi = (p-1)*(q-1) N = p*q print("p=", p) print("q=", q) # player_e = 65537 # player_d = pow(player_e, -1, phi) player_e = 1 player_d = 1 print("player_e=", player_e) print("player_d=", player_d) r.recvuntil(b">>") r.sendline(str(player_e).encode()) r.recvuntil(b">>") r.sendline(str(player_d).encode()) r.recvuntil(b"***") roundline = r.recvline() print("roundline", roundline) print(r.recvuntil(b"--> ")) deck = r.recvline().strip().decode() deck = ast.literal_eval(deck) # print("recv deck", deck) test_item = deck[0] found_seed = None for seed in tqdm.trange(2**10): prng = PRNG(seed) rand_values = [] for i in range(256): rand_values.append(prng.getnum()) found = False for offset in range(249): e_array = [str(x) for x in rand_values[offset:offset+6]] computer_e = int(''.join(e_array)) if gcd(computer_e, phi) != 1: continue computer_d = pow(computer_e, -1, phi) test_card = long_to_bytes(pow(test_item, computer_d, N)).decode('iso-8859-1') if test_card in deck_str: print("found seed", test_card, seed) found = True found_seed = seed break if found: break prng = PRNG(found_seed) computer_e, computer_d = -1, 0 for rndnum in range(10): if rndnum > 0: print(r.recvuntil(b"***")) roundline = r.recvline() print("roundline", roundline) print(r.recvuntil(b"--> ")) deck = r.recvline().strip().decode() deck = ast.literal_eval(deck) # print("recv deck", deck) computer_e, computer_d, server_deck = sim_round(server_deck, prng, phi, computer_e, computer_d) print(computer_e, computer_d, prng.seed, prng.index, prng.state) dec_cards = [] for enc_card in deck: dec_card = long_to_bytes(pow(enc_card, computer_d, N)).decode() dec_cards.append(card_str_to_Card(dec_card)) print([str(c) for c in dec_cards]) print([str(c) for c in server_deck]) while True: random.shuffle(dec_cards) computer_cards, player_cards = dec_cards[0:5], dec_cards[5:10] computer_winner, player_winner = determine_winner(computer_cards, player_cards) if player_winner and not computer_winner: break server_deck = list(dec_cards) enc_deck = [] for card in dec_cards: enc_deck.append(pow(bytes_to_long(str(card).encode()),computer_e,N)) for c in enc_deck: r.recvuntil(b">> ") r.sendline(str(c).encode()) r.recvuntil(b"HAHAHA") r.recvline() val = ast.literal_eval(r.recvline().decode()) print(long_to_bytes(pow(bytes_to_long(val),computer_d,N))) if __name__ == "__main__": exploit()