VCTF 2024 Crypto/Re 复现
Re
真ez
解题分析:
直接ida打开,分析代码
我们跟进sub_1492和sub_16B3两个函数看看
是一个RC4加密过程,即把flag进行了RC4加密
然后跟进sub_1249函数看一下,可以发现是一个base64编码(如果不知道的话可以扔给chatGPT让它帮忙分析,也可以得到是base64编码)
最终得到密文s1=‘3pn1Ek92hmAEg38EXMn99J9YBf8=’(说实话这个数据一看也可以知道是base编码了)
所以我们先进行base64解码,我直接在线网站解码,不行,这应该不是常规的base64编码,应该换表了,我们跟进base64编码代码看一下
得到base编码的表
0123456789XYZabcdefghijklABCDEFGHIJKLMNOPQRSTUVWmnopqrstuvwxyz+/
然后再进行解码(可以拿脚本,或者在线网站都行)
python脚本:(这个要方便很多)
import base64
import string
str1 = "3pn1Ek92hmAEg38EXMn99J9YBf8="#密文
string1 = "0123456789XYZabcdefghijklABCDEFGHIJKLMNOPQRSTUVWmnopqrstuvwxyz+/"#更改后的base64表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#原base64表
data=base64.b64decode(str1.translate(str.maketrans(string1,string2)))
print(list(data))
在线网站:
在线自定义base64编解码、在线二进制转可打印字符、在线base2、base4、base8、base16、base32、base64–查错网 (chacuo.net)
可以得到RC4加密后的密文:
[15, 60, 65, 117, 114, 66, 83, 6, 93, 76, 50, 29, 42, 92, 73, 38, 34, 75, 105, 34]
直接套用加密代码解密即可,密钥key跟进得到"Thi5_1S_key?"
#include <stdio.h>
#include <string.h>
int main(){
int i,j;
char a1[128],v9[128];
char key[]="Thi5_1S_key?";
int key_len=strlen(key);
char flag[]={15, 60, 65, 117, 114, 66, 83, 6, 93, 76, 50, 29, 42, 92, 73, 38, 34, 75, 105, 34};
int len=strlen(flag);
for ( i = 0; i <= 127; ++i ){
*(i + a1) = i;
*(v9 + i) = *(i % key_len + key);// 循环放入key
}
int v3,v5;
int v8=0;
for ( j = 0; j <= 127; ++j )
{
v3 = v8 + *(j + a1) + *(v9 + j);
v8 = (((v3 >> 25) + v8 + *(j + a1) + *(v9 + j)) & 0x7F) - (v3 >> 25);
v5 = *(j + a1);
*(j + a1) = *(v8 + a1);
*(a1 + v8) = v5; // 打乱顺序
}
int i1 = 0,result;
int v7 = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( i >= len )
break;
i1 = (i1 + 1) % 128;
v3 = *(i1 + a1) + v7;
v7 = (((v3 >> 25) + *(i1 + a1) + v7) & 0x7F) - (v3 >> 25);
v5 = *(i1 + a1);
*(i1 + a1) = *(v7 + a1);
*(a1 + v7) = v5;
*(flag + i) ^= *(((*(i1 + a1) + *(v7 + a1)) & 0x7F) + a1);
}
for(i=0;i<len;i++)
printf("%c",flag[i]);
// flag{Simple_rEvErse}
return 0;
}
答案:flag{Simple_rEvErse}
vm?
还不是很理解,等我再学习一下再来,主要是虚拟机不太熟
Crypto
狂飙
题目:
import os
from flag import flag
from Crypto.Util.number import *
from Crypto.Cipher import AES
m = 88007513702424243702066490849596817304827839547007641526433597788800212065249
key = os.urandom(24)
key = bytes_to_long(key)
n=m % key
flag += (16 - len(flag) % 16) * b'\x00'
iv = os.urandom(16)
aes = AES.new(key,AES.MODE_CBC,iv)
enc_flag = aes.encrypt(flag)
print(n)
print(enc_flag)
print(iv)
#103560843006078708944833658339172896192389513625588
#b'\xfc\x87\xcb\x8e\x9d\x1a\x17\x86\xd9~\x16)\xbfU\x98D\xfe\x8f\xde\x9c\xb0\xd1\x9e\xe7\xa7\xefiY\x95C\x14\x13C@j1\x9d\x08\xd9\xe7W>F2\x96cm\xeb'
#b'UN\x1d\xe2r<\x1db\x00\xdb\x9a\x84\x1e\x82\xf0\x86'
解题分析:
题目是一个AES的CBC加密,那么解密的话最关键的就是如何求到key了
这里key是24字节的,所以key的二进制长度范围可以得到(184,192]
根据n=m%key有m=k*key+n
即 m-n=k*key
这也意味着m-n是key的倍数,我们试一下分解m-n(尝试了一下暴力,数据太大跑不出来)
m-n=
88007513702424243702066490746035974298749130602173983187260701596410698439661
factor网站分解:http://factordb.com/index.php?query=322831561921859
得到[3,37,439,3939851,265898280367,5036645362649,342291058100503482469327892079792475478873]
以上这些数都是m-n的因子(这里我试了几次,写了三重循环得到答案)
from Crypto.Util.number import *
from Crypto.Cipher import AES
import os
m = 88007513702424243702066490849596817304827839547007641526433597788800212065249
n=103560843006078708944833658339172896192389513625588
enc_flag=b'\xfc\x87\xcb\x8e\x9d\x1a\x17\x86\xd9~\x16)\xbfU\x98D\xfe\x8f\xde\x9c\xb0\xd1\x9e\xe7\xa7\xefiY\x95C\x14\x13C@j1\x9d\x08\xd9\xe7W>F2\x96cm\xeb'
iv=b'UN\x1d\xe2r<\x1db\x00\xdb\x9a\x84\x1e\x82\xf0\x86'
mn=m-n
#88007513702424243702066490746035974298749130602173983187260701596410698439661
str=[3,37,439,3939851,265898280367,5036645362649,342291058100503482469327892079792475478873]
for i in str:
for j in str:
for k in str:
key=mn//(i*j*k)
key=long_to_bytes(key)
if len(key)==24 :
aes = AES.new(key,AES.MODE_CBC,iv)
flag = aes.decrypt(enc_flag)
if b'flag' in flag:
print(flag)
break
#flag{cf735a4d-f9d9-5110-8a73-5017fc39b1b0}
答案:flag{cf735a4d-f9d9-5110-8a73-5017fc39b1b0}
RRSA
题目:
from flag import flag
import random
from Crypto.Util.number import *
def genprime():
o = getPrime(300)
while True:
r = random.randint(2**211,2**212)
if isPrime(o*r+1):
return o,o*r+1
o1,p = genprime()
o2,q = genprime()
n=p*q
g = random.randint(2,n)
order = o1*o2
a = pow(g, (p-1)*(q-1)//order, n)
assert pow(a,order,n)==1
m = bytes_to_long(flag)
e = 65537
c = pow(m,e,n)
print(f'n={n}')
print(f'c={c}')
print(f'a={a}')
print(f'o={order}')
n=44435425447782114838897637647733409614831121089064725526413247701631122523646623518523253532066782191116739274354991533158902831935676078270115998050827358178237970133151467497051097694866238654012042884894924846645692294679774577780414805605811029994570132760841672754334836945991390844881416693502552870759
c=41355409695119524180275572228024314281790321005050664347253778436753663918879919757571129194249071204946415158483084730406579433518426895158142068246063333111438863836668823874266012696265984976829088976346775293102571794377818611709336242495598331872036489022428750111592728015245733975923531682859930386731
a=39844923600973712577104437232871220768052114284995840460375902596405104689968610170336151307934820030811039502338683925817667771016288030594299464019664781911131177394369348831163266849069740191783143327911986419528382896919157135487360024877230254274474109707112110411601273850406237677432935818199348150470
o=1745108106200960949680880500144134006212310627077303652648249235148621661187609612344828833696608872318217367008018829485062303972702933973340909520462917612611270028511222134076453
解题过程:
这道题好神奇,没见过这种,主要考的点居然是位数差异的问题,其实很简单,但是好难想到啊
n=pq=(o1r1+1)**(o2*r2+1)=o1o2r1r2+o1r1+o2r2+1
那么n//o1o2=r1r2+r1/o2+r2/o1+1/o1o2
根据
def genprime():
o = getPrime(300)
while True:
r = random.randint(2211,2212)
if isPrime(or+1):
return o,or+1
可以知道o1,o2都是二进制位数300的数,而r1,r2的二进制数在211-212之间
则o1,o2均比r1,r2要大
所以n//o1o2=r1r2(整除,后面的都是小数可以丢掉)
那么phi=r1r2o1o2=(n//o)*o
剩下的正常解即可得到flag
from Crypto.Util.number import *
from gmpy2 import *
n=44435425447782114838897637647733409614831121089064725526413247701631122523646623518523253532066782191116739274354991533158902831935676078270115998050827358178237970133151467497051097694866238654012042884894924846645692294679774577780414805605811029994570132760841672754334836945991390844881416693502552870759
c=41355409695119524180275572228024314281790321005050664347253778436753663918879919757571129194249071204946415158483084730406579433518426895158142068246063333111438863836668823874266012696265984976829088976346775293102571794377818611709336242495598331872036489022428750111592728015245733975923531682859930386731
a=39844923600973712577104437232871220768052114284995840460375902596405104689968610170336151307934820030811039502338683925817667771016288030594299464019664781911131177394369348831163266849069740191783143327911986419528382896919157135487360024877230254274474109707112110411601273850406237677432935818199348150470
o=1745108106200960949680880500144134006212310627077303652648249235148621661187609612344828833696608872318217367008018829485062303972702933973340909520462917612611270028511222134076453
e = 65537
rr=n//o
phi=rr*o
d=invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
答案:flag{0228FC7F-C865-BD0F-F124-9F9860B3542B}
收获:
1.对于n=m%key求key可以对m-n分解再进行暴力破解
2.在做题的时候如果给了位数,要注意一下,可能这就是突破点
3.base64换表的脚本可以存下