虎符CTF2020 writeup

badmonkey 2020年04月19日 527次浏览

虎符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吧,类似海明校验码,应该挺有意思的。