虎符CTF2020 writeup
GM
概率密码题,不过由于一开始眼花,看错了题目导致做了很久。这道题其实没什么难度。类似今年1月pwnhub的考点。但是简单很多。直接贴上wiki,大致意思就是根据勒让的符号判断。message的每一位。不过需要分解N,分解的过程就是解一个二次方程,exp如下:
from gmpy2 import *
from Crypto.Util.number import *
phi = "......."
N = "......"
x = "......"
delat = iroot(x**2 - 4*N,2)[0]
p = (x-delat)//2
q = N//p
assert p*q == N
cipher = "......"
flag = ""
for i in cipher:
if legendre(i,p) == 1:
flag += '0'
else:
flag += '1'
print flag
flag = int(flag,2)
print long_to_bytes(flag)
pell
没想到,大型比赛会出这种题。跟密码的关系真不大。google 一顿搜索发现一篇结论性的文章。本以为会快速结束战斗继续看mceliece。没想到出现了很多状况,也当时经验教训吧。
没有仔细审题。
题目中要求解的x,y都是512位以内的。但是到比赛结束前一个小时都没有考虑到。浪费了很多精力。
谜之交互
以前做交互题,都是用的minipwn,也没有遇到什么大问题。但是这次算是栽了。交互最好还是用pwntools。当然效果都是一样的,需要注意的是,如果需要连续发包,一定要设置时间间隔,不然会出现各种鬼畜的情况,题目环境本身是没有问题的,但是脚本写的不好的话,各种情况都可能发生。而且也没有准备相应的proof_work脚本,于是本懒狗这次就写了一个以备不时之需:
#! /bin/bash/env python3
def byte2str(mess):
if type(mess) == str:
return mess
res = ""
for i in mess:
res += chr(i)
return res
def proof_work(bytes,known,hash):
all = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
known = byte2str(known)
hash = byte2str(hash)
for i in permutations(all,bytes):
guess = ''.join(i)
if sha256((guess+known).encode()).hexdigest() == hash:
return guess
本地测试
其实如果,习惯性的在本地测试一下脚本,再打过去的话,效率会高很多,至少连续发包的问题能够及时发现。下次一定本地测试一下,再打过去,不然真是盲人摸象。
最后,把这道题重做了一下,本地是可以打通的,但是莫名奇妙的是远程打不通。。难道还有啥问题需要注意,等官方wp出来再学习一下。不知道对不对的脚本:
from hashlib import sha256
from gmpy2 import *
from pwn import *
from itertools import permutations
from time import sleep
address = "39.97.210.182"
port = 61235
#address = "127.0.0.1"
#port = 11111
def byte2str(mess):
if type(mess) == str:
return mess
res = ""
for i in mess:
res += chr(i)
return res
def proof_work(bytes,known,hash):
all = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
known = byte2str(known)
hash = byte2str(hash)
for i in permutations(all,bytes):
guess = ''.join(i)
if sha256((guess+known).encode()).hexdigest() == hash:
return guess
def find_one(a,b):
if b!=1 or iroot(a,2)[1]:
return (-1,-1)
y = 1
while True:
res = iroot(a*y**2+b,2)
if res[1]:
return (res[0],y)
y += 1
def find_all(x,y,a,b):
tx = int(x)
ty = int(y)
for _ in range(149):
tx, ty = tx * x + ty * y * a, x * ty + y * tx
assert tx * tx - a * ty * ty == 1
yield (tx,ty)
def login(io):
res = io.recvline()
print(res)
known = res[12:28]
hash = res[-65:-1]
xxxx = proof_work(4,known,hash)
io.sendline(xxxx)
def attack(io):
while True:
try:
login(io)
except:
io.close()
io = remote(address,port)
attack(io)
return
print(io.recvline())
info = io.recvline()
print(info)
a = int(info[10:12])
b = int(info[-2:-1])
print(a,b)
if (a == 15 and b==1) or (a == 24 and b==1):
print("good pairs")
res = find_one(a, b)
break
else:
print("bad pairs")
io.close()
io = remote(address,port)
attack(io)
return
x, y = res
io.sendline(str(x))
io.sendline(str(y))
cnt = 1
pos = 0
g = find_all(x,y,a,b)
print("starting...")
# io.interactive()
while True:
print(cnt)
xx,yy = next(g)
if xx.bit_length()>512 or yy.bit_length()>512:
io.close()
io = remote(address,port)
attack(io)
return
print(xx**2 == a*yy**2+b)
# print(xx,yy)
io.sendline(str(xx))
sleep(1.5)
io.sendline(str(yy))
sleep(1.5)
cnt += 1
if cnt==150:
break
pos += 1
io.interactive()
io = remote(address,port)
attack(io)
mceliece
看一下,因该是这篇paper其中的攻击方式,不过没时间做了,等wp吧,类似海明校验码,应该挺有意思的。