import socket, select, signal, string
import sys, os, time, random
import threading
HOST = '198.51.100.0'
PORT = 1337
USERNAME = "Houdini"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), PORT))
key = int(s.recv(1240).decode("utf-8").split(" ")[1])
def encrypt(plaintext):
global USERNAME
global key
plaintext = USERNAME + ": " + plaintext
out = [random.randint(0, 9999), random.randint(0, 999)]
for i in range(len(plaintext)):
out.append((out[i+1] + ((out[i] * ord(plaintext[i])) ^ (key+out[i+1]))) ^ (key*out[i]))
import socket, select, signal, string
import sys, os, time, random
import threading
HOST = '198.51.100.1'
PORT = 1337
USERNAME = "nnewram"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((socket.gethostname(), PORT))
key = int(s.recv(1240).decode("utf-8").split(" ")[1])
def encrypt(plaintext):
global USERNAME
global key
plaintext = USERNAME + ": " + plaintext
out = [random.randint(0, 9999), random.randint(0, 999)]
for i in range(len(plaintext)):
out.append((out[i
import socket, threading
import sys, os
import random, signal
PORT = 1337
KEY = random.randint(0, 100000000000000000000000)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(), PORT))
s.listen(5)
client_list = []
def relay_message(message, sender):
global client_list
for client in client_list:
if client != sender:
try:
client[0].send(message)
except:
client[0].close()
client_list.remove(client)
def client_reciever(socket):
print(socket)
while True:
message = socket[0].recv(500000)
if not message:
break
print("Message from: " + socket[1][0] + "\nContent: " + message.decode("utf-8"))
relay_message(message, socket)
def main():
while True:
client, address = s.accept() # accept all incomming clients
client_list.append((client, address))
print("Incomming user: " + address[0])
client.send(bytes("KEY: " + str(KEY), "utf-8"))
client_thread = threading.Thread(target=client_reciever, args=((client, address), ))
client_thread.start()
#this is only for closing the sockets after sigsegv
def handler_signals(signum, frame):
global run
global s
s.close()
print("----Closed Server----")
sys.exit()
signal.signal(signal.SIGINT, handler_signals)
signal.signal(signal.SIGTERM, handler_signals)
#this is only for closing the sockets after sigsegv
main()
通过代码审计找到加密函数:
out.append((out[i+1] + ((out[i] * ord(plaintext[i])) ^ (key+out[i+1]))) ^ (key*out[i]))
可知,只要知道out和key就能求解出明文
out就是 conversation 加密对话内容
所以解题的关键是求解key
由 KEY = random.randint(0, 100000000000000000000000) 得k的位数是76位
其次,我们其实是知道一部分明文的,因为
plaintext = USERNAME + ": " + plaintext
而USERNAME是知道的,就拿 USERNAME = "Houdini:" 举例,包括冒号共知道10个字符,
且知道加密代码:
((out[i + 1] + ((out[i] * ord(plain[i])) ^ (key + out[i + 1]))) ^ (key * out[i]))==out[i+2]
就可以得到10个方程,用z3去求解
不同的位数都可能求出key值,大概由七十六七个,爆破这些key来找到可用于解密的key
from z3 import *
from tqdm import tqdm
#print(len(bin(100000000000000000000000)[2:]))'
def decrypt():
out=[8886, 42, 212351850074573251730471044, 424970871445403036476084342 ,5074088654060645719700112791577634658478525829848, 17980375751459479892183878405763572663247662296, 121243943296116422476619559571200060016769222670118557978266602062366168 ,242789433733772377162253757058605232140494788666115363337105327522154016 ,2897090450760618154631253497246288923325478215090551806927512438699802516318766105962219562904, 7372806106688864629183362019405317958359908549913588813279832042020854419620109770781392560]
plain='Houdini:'
keys=[]
for k in tqdm(range(1,78)):
key=BitVec('key',k)
s=Solver()
for i in range(8):
s.add(((out[i + 1] + ((out[i] * ord(plain[i])) ^ (key + out[i + 1]))) ^ (key * out[i]))==out[i+2])
s.check()
res=s.model()
res = res[key].as_long()
#print(res)
flag=''
cs=open("conversation").readlines()
for i in range(1,len(cs),2):
ct=cs[i].split(" ")
for i in range(1,len(ct)):
ct[i]=int(ct[i])
for j in range(1,len(ct)-2):
try:#out[i+2]=(out[i+1] + ((out[i] * ord(plaintext[i])) ^ (key+out[i+1]))) ^ (key*out[i])
pt=((((res*ct[j])^ct[j+2])-ct[j+1])^(res+ct[j+1]))//ct[j]
flag+=chr(pt)
except:
continue
if "watevr{" in flag:
print(flag)
break
decrypt()