2020_WHUCTF_Writeup(部分)

0x1 crypto

bvibvi

首先要通过验证问题,对一个等式计算求解,简单的枚举求解即可。
通过验证过后,需要回答一系列问题,是关于B站BV号和AV号的。
题目给出BV号,让我们找出对应的AV号。多组正确后再给AV号,让我们找出BV号。
简单的了解了下Bilibili的av号和bv号知识后,发现

av号对应url格式为 url =‘https://www.bilibili.com/video/av’+aid
bv号为 url =‘https://www.bilibili.com/video/’+bid

若手工一一查找太麻烦,另外程序也有时间限制,因此需要采取自动化办法获取av和bv对应关系。
可通过在网页源码查看对应的BV和AV,利用python re模块进行提取即可。
在这里插入图片描述
解题脚本

from pwn import *
import requests
r = remote('218.197.154.9' ,'16387')

context(log_level='debug')
print(string.printable)
def work():
    r.recvuntil('Math:\n')
    d1 =r.recvuntil(' *')[:-2]
    
    r.recvuntil('+ ')
    d2 = r.recvuntil(' ')
    r.recvuntil('== ')
    d3 = r.recvuntil(' ')
    r.recvuntil('mod ')
    d4 = r.recvuntil('\n')[:-1]
    d1,d2,d3,d4 = int(d1),int(d2),int(d3),int(d4)
    #print(int(d1),d2,d3,d4)
    for x in range(d4):
        if (d1*x+d2) % d4 == d3:
            print(x)
            r.sendlineafter('x :',str(x))
def bv():
    i=5
    while i:
        i=i-1
        aid = r.recvuntil('\n')[:-1]
        url ='https://www.bilibili.com/video/av'+aid
        q = requests.get(url)
        res = re.findall(r'"videoData":{"bvid":"(.*)","aid":(.*),"videos"',q.text)
        print(res[0][0])
        r.sendline(res[0][0])

def av():
    sleep(1)
    i=15
    while i:
        i=i-1
        bid = r.recvuntil('\n')[:-1]
        url ='https://www.bilibili.com/video/'+bid
        q = requests.get(url)
        res = re.findall(r'"videoData":{"bvid":"(.*)","aid":(.*),"videos"',q.text)
        #print(res[0][1])
        r.sendline(res[0][1])


work()
r.recvuntil('id.\n')
bv()
r.recvuntil('number.\n')
av()

print(r.recvall())

notrsa

关于rsa的题目。
题目给了p q e c,但其中p不是素数,因此需要进一步对p分解,否则直接解密会出错。
借助yafu分解p
在这里插入图片描述
所有相当于RSA模数有三个素因子,利用欧拉定理得到
phi = (p1-1)*(p2-1)*(q-1)
于是可求出私钥d=invert(e,phi)
明文 flag = pow(c,d,p*q)

脚本

#!/usr/bin/env python

from Crypto.Util.number import *
import gmpy2
p = 0x501431403e46f960310474f59accb2cb
q = 0xb0b378d96238e799a2e544e7686f8d17
e = 0x10001
c = 0x9b941cce29810d1026e0005c1bd20f4234f7f210edd3ed369cdd3ff7b34c188


p1 = 10215054443853430669
p2 = 10420217054443542967

phi = (p1-1)*(p2-1)*(q-1)
d = gmpy2.invert(e,phi)
m = pow(c,d,(p*q))
print(m)
print(long_to_bytes(m))

aes

cbc模式加密。加密方式如下

def aes_pad(s):
    t = bytes((AES_KEYSIZE - len(s) % AES_KEYSIZE) * chr(AES_KEYSIZE - len(s) % AES_KEYSIZE),
              encoding='utf-8')
    return s + t


def enc():
    f = open('plaintext', 'r')
    plaintext = f.readlines()
    f.close()
    f = open('ciphertext', 'w')
    for i in range(len(IV)):
        aes = AES.new(key, AES.MODE_CBC, IV[i])
        m = aes_pad(base64.b64decode(plaintext[i]))
        cipher = aes.encrypt(m)
        print(bytes.decode(base64.b64encode(cipher)), file=f)
    f.close()

本题密钥已知,密文已知,但初始化IV未知。

AES算法的IV长度为16字节,暴力破解是不现实的。

cbc模式解密模式如下。在第二组密文解密时并不受到IV值影响,只需要有key和前一组密文即可。
在这里插入图片描述
所以可以获取到每行明文的第二个数块以及之后的数据块。

编写脚本尝试解密,看是否有发现

import string

def unpad(s):
    t=0
    #print((s[-1]))
    return s[:-s[-1]]

def dec():
    f = open('ciphertext', 'r')
    cipher = f.readlines()
    f.close()
    f = open('plaintext1', 'w')
    flag=''
    for i in range(len(cipher)):
        ci = (base64.b64decode(cipher[i]))
        iv=b'\x00'*16    #iv可以任意
        aes = AES.new(key, AES.MODE_CBC,iv)
        #m = aes.decrypt(ci[16:]+ci[:16])
        m = aes.decrypt(ci)
        #print(m)
        m=unpad(m)
        #print(m,len(m))
        flag+=chr(m[-1])

        #print(base64.b64encode(m), file=f)
    print(flag[::-1])
    #print(''.join(flag))
    f.close()

dec()

仔细观在这里插入图片描述察解密后的数据,发现每行最后一个字节是明文,组合起来便是flag。出题人太会玩了。
需要注意解密后要进行unpad操作才能能得到原始m。

prism

这道题涉及到了RSA密码问题、离散对数密码问题。加密计算过程虽然复杂,但做题思路很清晰。
加密脚本

def enc(keys, m):
    p, g, y = keys[-1]
    while True:
        k = getRandomInteger(2048)
        if gmpy2.gcd(k, p-1) == 1:
            break
    c1 = pow(g, k, p)
    m = (getRandomInteger(64) << m.bit_length()) + m
    m = ((m << 64) + getRandomInteger(64))
    c2 = pow(y, k, p) * m % p
    return c1, c2

密钥来源

from Crypto.Util.number import getPrime, getRandomInteger, long_to_bytes, bytes_to_long
from Crypto.Cipher import AES
from Crypto.Util import Counter
import gmpy2

from secret import rsa_keygen


def FFF(food, key):    #aesjiami
    K = 0xe238c70fe2d1885a1b12debfa15484cab8af04675c39ff4c633d6177f234ed88
    key = long_to_bytes(key, 32)
    food = long_to_bytes(food, 128)
    aes = AES.new(key, AES.MODE_CTR, counter=Counter.new(128, initial_value=K))
    c = bytes_to_long(aes.encrypt(food))
    return c
    

def GGG(food, key):
    K = 0xfd94d8de73e4aa8f4f452782b98a7870e82ec92a9db606fe4ca41f32d6df90c5
    K = long_to_bytes(K, 32)
    food = long_to_bytes(food, 128)
    aes = AES.new(K, AES.MODE_CTR, counter=Counter.new(128, initial_value=key))
    c = bytes_to_long(aes.encrypt(food))
    return c
    

def keygen():
    keys = []
    
    n0, e0 = rsa_keygen()
    keys.append([n0, e0])
    N0, E0 = n0, e0
    
    while True:
        p1 = getPrime(1024 // 2)
        e1 = pow(p1, E0, N0)
        q1 = getPrime(1024 // 2)
        n1 = p1 * q1
        phi1 = (p1-1)*(q1-1)
        if e1 < n1 and gmpy2.gcd(e1, phi1) == 1:
            break
    keys.append([n1, e1])
    N1, E1 = n1, e1

    K2 = 0xb6a022cd2fb960d4b6caa601a0412918fd80656b76c782fa6fe9cf50ef205ffb
    B2_1 = 8
    B2_2 = 8
    B2_3 = 1024
    while True:
        p2 = getPrime(2048 // 2)
        i = 0
        while True:
            p2_1 = FFF(p2, K2 + i)    #aes encrypt,i not known  (0,8)
            if p2_1 < N1:
                break
            i += 1
            if i >= B2_1:
                break
        if i >= B2_1:
            continue
        p2_2 = pow(p2_1, E1, N1)
        j = 0
        while True:
            p2_3 = GGG(p2_2, K2 + j)
            x2 = (p2_3 << 1024) + getRandomInteger(1024)
            q2 = gmpy2.next_prime(x2 // p2)
            n2 = p2 * q2
            if 0 <= (n2 >> 1024) - p2_3 < B2_3:
                break
            j += 1
            if j >= B2_2:
                break
        if i <= B2_1 and j < B2_2:
            break
    e2 = 65537
    keys.append([n2, e2])
    N2, E2 = n2, e2

    K3 = 0xfcec710a0313bb8f93e76e00ae6862b9be72dfd837db3b64ddde344bebfd2f50
    B3_1 = 8
    B3_2 = 1024
    while True:
        x3 = gmpy2.next_prime(getRandomInteger(2048) % N2)
        if x3 >= N2:
            continue
        x3_2 = pow(x3, E2, N2)
        i = 0
        while True:
            f3 = FFF(x3_2, K3 + i)
            p3 = gmpy2.next_prime(f3)
            if p3 > x3 and p3 - f3 < B3_2:
                break
            i += 1
            if i >= B3_1:
                break
        if i < B3_1:
            break
    while True:
        g3 = gmpy2.next_prime(getRandomInteger(p3.bit_length()) % p3)
        if g3 < p3 and 1 == gmpy2.gcd(g3, p3-1):
            break
    y3 = pow(g3, x3, p3)
    keys.append((p3, g3, y3))
    P3, G3, Y3 = p3, g3, y3

    B4 = 16384
    while True:
        x4 = gmpy2.next_prime(getRandomInteger(2048) % P3)
        k = getPrime(2048)
        if x4 >= P3 or gmpy2.gcd(k, P3-1) > 1:
            continue
        b4 = pow(Y3, k, P3) * x4 % P3
        p4 = gmpy2.next_prime(b4)
        g4 = pow(G3, k, P3)
        if gmpy2.is_prime(p4) and x4 < p4 and g4 
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值