writeups/2023/csawq/attack_poker.py

162 lines
4.5 KiB
Python

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()