2024H&NCTF 密码组部分出题记录
题目:BabyPQ、HappyDance
文章目录
- 2024H&NCTF 密码组部分出题记录
- BabyPQ | 签到
- HappyDance
BabyPQ | 签到
本题为nc交互题,之所以采用这种形式,是因为可能有很多密码新师傅们不了解这种赛题形式,但在国赛中这种形式采用的比较频繁,在2023年的国赛中两道密码都是nc题,所以在这里为密码新师傅们记录一下nc的使用方式
nc ip 端口
那么针对该题目,主要考查的是师傅们对欧拉函数的理解,以及解方程的能力
相当于去利用并构造韦达定理,得到的解中
x 1 ∗ x 2 = c a x 1 + x 2 = − b a x_1*x_2 = \frac c a \\ x_1 + x_2 = - \frac b a x1∗x2=acx1+x2=−ab
其中x1和x2就是对应的p和q
exp:
from sympy import symbols, solven= 80775397981216739537937013140335212564179336161039465593344766173631256110488228325487563463294794963374779976831086300486337286970246697848047792010731877541279819395960988048577550565927738392401730097774622194491797027279131382261701828206975149412522479597626213186391007855189654805110759477917127546597
phin= 80775397981216739537937013140335212564179336161039465593344766173631256110488228325487563463294794963374779976831086300486337286970246697848047792010731859489034712266817839739752550468696547302928830348317740718020226750115933170808890435181672724707888679013080731047467878099779880689498143333491504209036# 定义符号变量
x = symbols('x')# 定义方程
equation = x**2 - (n+1-phin)*x + n# 解方程
solutions = solve(equation, x)# 输出解
print("方程的解为:", solutions)
解有两个,有两次机会,都试一下就知道哪个是p咯
HappyDance
题目:
#!/usr/local/bin/python
from chacha20 import *
from Crypto.Util.number import long_to_bytes, bytes_to_long
from secret import flag, mykey, mynoncedef chacha_init(key, nonce, counter):assert len(key) == 32assert len(nonce) == 8state = [0 for _ in range(16)]state[0] = bytes_to_long(b"expa"[::-1])state[1] = bytes_to_long(b"nd 3"[::-1])state[2] = bytes_to_long(b"2-by"[::-1])state[3] = bytes_to_long(b"te k"[::-1])key = bytes_to_long(key)nonce = bytes_to_long(nonce)for i in range(8): state[i+4] = key & 0xffffffffkey >>= 32state[12] = (counter >> 32) & 0xffffffffstate[13] = counter & 0xffffffffstate[14] = (nonce >> 32) & 0xffffffffstate[15] = nonce & 0xffffffffreturn statedef encrypt(data):global statestate = chacha_block(state)buffer = b"".join(long_to_bytes(x).rjust(4, b"\x00") for x in state)output = []for b in data:output.append(b ^ buffer[0])buffer = buffer[1:]return bytes(output)FLAG = b"H&NCTF{****FAKE****}"
MYNONCE =b"s*f*h*o*"
assert len(flag) == 64
assert len(mynonce) == 8if __name__ == "__main__":while True:print("""================================
Enjoy the happiness of dancing
1. Dance on My Stage
2. Dance on Your Stage
3. Encrypt flag
""")choice = input("> ")if choice == '1':state = chacha_init(mykey, mynonce, 0)print(encrypt(input("input what you want to dance on my stage > ").encode()).hex()) elif choice == '2':yournonce = input("build your own stage > ")assert len(yournonce) == 8state = chacha_init(mykey, yournonce.encode(), 0)yourIn = bytes.fromhex(input("then, have a hex dance > "))print(encrypt(yourIn).hex())elif choice == '3':state = chacha_init(mykey, mynonce[::-1], 0) print(encrypt(flag).hex())else:print("Let's dance together next time~")exit()
这个题目的设计,其实本身没有想考师傅们对于chacha20具体实现,因为题目中对于chacha20的部分代码选择了隐藏,就是在from chacha20 import *
这一块中,也是侧面想提醒师傅们,不需要深究其变换过程。
那么通过一张图展示chacha20的结果性质
非常清晰的可以看到状态转化后生成的key和明文最后只进行了一步异或操作就得到密文了
同时初始化生成的内容又是固定的,在咱们这个题目中,未知的也可以说是可控的只有nonce咯
只要初始化相同,后面经过相同轮次的状态转换生成的key是完全一致的
以上就是本地的核心考点,希望能通过本地让师傅们了解一下chacha20算法,一些具体的过程可以参考之前写的一篇wp:记录一道关于chacha20算法的密码题
针对本题的解法就是,首先利用选项1和2去恢复我们nonce的隐藏位,然后利用3获取flag的密文,同时我们也知道flag密文的生成是利用了nonce的逆序,所以最后一步是直接使用2,构建nonce逆序的初始化,然后直接把密文输进去就好,因为题目本身也是对flag的长度进行了限制。
步骤一:恢复MYNONCE
from pwn import *
context(log_level='debug')
#启动debug模式,可以看到交互时候的传输信息,怕有些信息收不到debug就开一下io = remote('hnctf.imxbt.cn',30295) #表示交互的目标import string
MYNONCE = b"sdf*h*o*"
for x1 in string.ascii_lowercase:for x2 in string.ascii_lowercase:for x3 in string.ascii_lowercase:io.recvuntil(b'> ')#接受到某个字符停下io.sendline(b'2')#发送某些字符并按下回车mynonce = MYNONCE.decode().replace('*', x1, 1).replace('*', x2, 1).replace('*', x3, 1)io.recvuntil(b'> ')#接受到某个字符停下io.sendline(mynonce.encode())io.recvuntil(b'> ')#接受到某个字符停下io.sendline(b'61736466')tmp = io.recvline()if tmp == b'b76d59fb\n':print("!!!", mynonce)exit()
一开始本来隐藏了四位,但是进入交互去爆破时间要1个小时,听了鸡块师傅的建议没必要这么久,就改成三位了,这个也就10分钟左右,此外在爆破的师傅注意一个点,就是首先通过选项1,用正确的MYNONCE生成一组数据,在利用选项2构造自己的nonce去和题目的MYNONCE做比较,但是生成数据的时候,尽量长一点,如果一个字符的话,非常有可能出现nonce不同,但是结果相同的情况
我这上面是用了四个字符asdf
传入到1 注意转成16进制传 然后返回的结果是b76d59fb
就利用这一组在选项2中爆破 即可恢复MYNONCE
步骤2:拿flag
首先利用选项3 拿到flag的密文
然后利用选项2 构建MYNONCE逆序的“舞台”
直接传入flag的密文,返回hex数据,转一下就拿到flag啦
后面这部分没有构建自动化脚本,为了更清楚的让师傅们看到这个题目的流程,后面会补充一下全自动化的脚本的!