[watevrCTF 2019]Crypto over the intrawebs Z3求解方程式

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Paintrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值