1024_密码系统
附件1024sys.py
# -*- coding:utf-8 -*-
# Author:airrudder
from Crypto.Cipher import DES
from binascii import b2a_hex, a2b_hex
from secret import FLAG,KEY,HINT
from itertools import *
import random
def Encode_1024sys(data,key):
data_list = [data[i:i+8] for i in range(0,len(data),8)]
k1 = DES.new(key.encode(), DES.MODE_ECB)
k2 = DES.new(key[::-1].encode(), DES.MODE_ECB)
data_res = ''
for i in range(0,len(data_list)):
k = random.choice([k1,k2])
c = k.encrypt(data_list[i].encode())
data_res += b2a_hex(c).decode()
return data_res
def Encode_1024(data,key):
len_data=len(data)
choices = cycle('1024')
while len_data%8!=0:
data += next(choices)
len_data=len(data)
data_res = Encode_1024sys(data,key)
data_out = hex(int(data_res,16)**12 + random.randint(10**1023,10**1024))[2:]
return data_out
def main():
menu = '''
1. Encode
2. Verify your FLAG
3. Exit
'''
try:
while True:
print(menu)
choice = input("> ")
if choice == "1":
msg=input("Please input your msg: ")
data_out = Encode_1024(msg+FLAG,KEY)
print("hex(Encode_1024(msg+flag)) is :",data_out)
elif choice == "2":
yourFLAG = input('Please input your FLAG: ')
if yourFLAG == FLAG:
print(HINT)
else:
print('1024, nonono..., come on!!!')
elif choice == "3":
print("Bye!")
return
else:
print("Invalid choice!")
continue
except:
print('error')
if __name__ == "__main__":
main()
这里解释主要参考Lazzaro师傅的wp:https://lazzzaro.github.io/2020/10/25/match-CTFshow-1024%E6%9D%AF/。
输出值是密文$c$经过$c{12}+rand(10{1023},10{1024})$处理的,
假设$c{12}+rand(10{1023},10{1024}) \lt(c+1){12}$,那么对输出值直接开12次方取整即为 $c$。
明文由输入值m+flag+padding
组成,$m$ 为空时,$c$ 可分 $k$ 块,不断调整 $m$ 的长度,直到 $m$ 长度为 $l+1$ 时 $c$ 可分 $k+1$ 块,那么说明 $m$ 长度为 $l$ 时 $c$ 刚好可分 $k$ 块,即无padding情况下,$m+flag$ 可分 $k$ 块,则flag长度即为 $8k−l$。
利用上面的思想,在 $m$ 长度为 $l$ 的基础上,长度不断加1,则可以把flag从后开始的每一位推到下一个块中,得到下一个块的密文 $ci$;
又已爆破出的flag位+padding
已知,则下一个块的构成为未知字符1位+已爆破出的flag位(+padding)
;
根据DES-ECB的性质,相同明文块对应的密文块相同。爆破第一位未知字符,将上面的块构成作为输入值输入,得到对应的密文的第一块,分别与实际密文 ci
比较,匹配的即为正确的明文字符。
此题padding是按照1024
顺次填充。
举个例子:
假设flag为 flag{12345678} #共14位
填充后 flag{12345678}10 #16位,明文分组为“flag{123”、“45678}10”
#flag前面的数据可控,假如填入的msg为“111”
flag会被填充到 111flag{12345678}1024102 #共24位,明文分组为“111flag{”、“12345678”、“}1024102”
#也就是说flag的最后一位“}”就被挤出了原来的分组,总长度增加。而且最后一个明文分组为“}1024102”。
#那么假如我在一开始填入的msg为“}1024102111”
flag会被填充到 }1024102111flag{12345678}1024102 #共32位,明文分组为“}1024102”、“111flag{”、“12345678”、“}1024102”
#这也就是说第一个明文分组和最后一个明文分组是一样的,所以ECB模式下,所对应的密文分组也一样。
#所以对输入的msg逐位添加爆破即可
爆破8位后,得到 2345678}1024102111flag{12345678} #共32位
#到第9位时,就需要比较第一个明文分组和倒数第二个明文分组所对应的密文分组是否一样了
12345678}1024102111flag{12345678}1024102 #共40位,明文分组“12345678”、“}1024102”、“111flag{”、“12345678”、“}1024102”
#同样的,到(8k+1)位是,需要比较第一个明文分组和倒数第(k+1)位的明文分组
exp
from pwn import *
import gmpy2
import string
import sys
import random
def main():
try:
sh = remote(sys.argv[1],sys.argv[2])
print('\n[+] 开始爆破FLAG')
FLAG = get_FLAG(sh)
print('\n[+] 开始解密得到flag')
flag = yunying(FLAG)
print('flag{'+flag.lower()+'}')
except:
print_msg()
exit(0)
def print_msg():
print('='*50)
print('Usage: python exp.py <ip> <port>')
print(' Eg: python exp.py 127.0.0.1 10248')
print('='*50)
#验证FLAG
def verify_FLAG(sh,FLAG):
sh.recvuntil('> ')
sh.sendline('2')
sh.recvuntil('Please input your FLAG: ')
sh.sendline(FLAG)
data = sh.recvline().decode()
if 'nonono' not in data:
print('\nHINT: '+data)
return FLAG
return 0
def get_FLAG(sh):
FLAG = ''
table = '1024'
# 不知道FLAG被分成几组,这里先爆破5组
for k in range(5):
#DES分组,每组8字节
for j in range(8):
#由于key有两个,不知道到底使用的哪一个,所以多循环几次爆破即可
while True:
i = random.choice(['1','0','2','4'])
sh.recvuntil('> ')
sh.sendline('1')
sh.recvuntil('Please input your msg: ')
payload = i+FLAG+'1024102111'
sh.sendline(payload)
#接收到的data数据
data = sh.recvline().decode().split(' : ')[1][:-1]
#print(data)
datadec = int(data,16)
#开方后十进制表示的数据
dec1024 = gmpy2.iroot(datadec,12)
hex1024 = hex(dec1024[0])[2:]
if (k==0 and hex1024[:16]==hex1024[-16:]) or hex1024[:16]==hex1024[-16*(k+1):-16*(k)]:
FLAG = i+FLAG
print('\rFLAG = '+FLAG,end='')
if verify_FLAG(sh,FLAG):
return FLAG
break
return 0
#云影密码(01248密码)解密
def yunying(FLAG):
flag = ''
strs = string.ascii_uppercase
flag_list = FLAG.split('0')
for j in flag_list:
tmp = 0
for k in j:
tmp += int(k)
flag += strs[tmp-1]
return flag
if __name__ == '__main__':
main()
得到flag:flag{yioersi}
个人文章:https://blog.csdn.net/hiahiachang/article/details/109283286