2024年全国大学生信息安全竞赛安徽省赛 # WriteUp
作者:乔不思
CRYPTO1 RSAROLL
下载得到文件
{920139713,19}
704796792
752211152
274704164
18414022
368270835
483295235
。。。。
1.文件的第一行
很可能是公钥(n,e),
其中n:920139713, e = 19。
2.接下来的数字列表应该是加密后的密文
要解决这个问题
1.因子分解n以获得p和q
2.计算欧拉函数p(n)=(p-1)(q-1)
3.计算私钥d=e^(-1)modp(n)4.对每个密文c进行解密:m=c^dmodn5.将解密后的数字转换为字符
from Crypto.Util.number import inverse, long_to_bytes
def factorize(n):
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return i, n // i
return None
n = 920139713
e = 19
p, q = factorize(n)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
ciphertext = [ 704796792, 752211152, 274704164, 18414022, 368270835, 483295235, 263072905, 459788476, 483295235, 459788476, 663551792, 475206804, 459788476, 428313374, 475206804, 459788476, 425392137, 704796792, 458265677, 341524652, 483295235, 534149509, 425392137, 428313374, 425392137, 341524652, 458265677, 263072905, 483295235, 828509797, 341524652, 425392137, 475206804, 428313374, 483295235, 475206804, 459788476, 306220148]
plaintext = ""
for c in ciphertext:
m = pow(c, d, n)
plaintext += long_to_bytes(m).decode('ascii', errors='ignore')
print(plaintext)
得到flag
CRYPTO2 RSA_GCD
下载附件,解压得到两个txt文件
这两个文件attach1.txt和attach2.txt
包含了两组RSA加密的数据:
1.两个文件都包含公钥(n,e)和密文c
2.两个文件使用了相同的公钥指数e=65537
3.两个文件的模数n是不同的:attach1.txt的n=23220619839642624...attach2.txt 的 n =22642739016943309...
4.密文c也是不同的。
这种情况下,我们可以尝试使用最大公约数(GCD)攻击来破解RSA。这种攻击方法适用于两个不同的RSA公钥共享一个质因子的情况。
攻击步骤如下:
1.计算两个模数n1和n2的最大公约数。
2.如果GCD(n1,n2)不等于1,那么我们找到了一个共同的质因子 p。
3.使用 p 来分解 n1 和 n2,得到另一个质因子 q。
4.有了p和q,我们就可以计算出私钥 d。
5.使用私钥d来解密密文c。
import math
def gcd(a, b):
while b:
a, b = b, a % b
return a
def main():
n1 = 23220619839642624127208804329329079289273497927351564011985292026254914394833691542552890810511751239656361686073628273309390314881604580204429708461587512500636158161303419916259271078173864800267063540526943181173708108324471815782985626723198144643256432774984884880698594364583949485749575467318173034467846143380574145455195152793742611717169602237969286580028662721065495380192815175057945420182742366791661416822623915523868590710387635935179876275147056396018527260488459333051132720558953142984038635223793992651637708150494964785475065404568844039983381403909341302098773533325080910057845573898984314246089
n2 = 22642739016943309717184794898017950186520467348317322177556419830195164079827782890660385734113396507640392461790899249329899658620250506845740531699023854206947331021605746078358967885852989786535093914459120629747240179425838485974008209140597947135295304382318570454491064938082423309363452665886141604328435366646426917928023608108470382196753292656828513681562077468846105122812084765257799070754405638149508107463233633350462138751758913036373169668828888213323429656344812014480962916088695910177763839393954730732312224100718431146133548897031060554005592930347226526561939922660855047026581292571487960929911
e = 65537
c1 = 9700614748413503291260966231863562117502096284616216707445276355274869086619796527618473213422509996843430296526594113572675840559345077344419098900818709577642324900405582499683604786981144099878021784567540654040833912063141709913653416394888766281465200682852378794478801329251224801006820925858507273130504236563822120838520746270280731121442839412258397191963036040553539697846535038841541209050503061001070909725806574230090246041891486506980939294245537252610944799573920844235221096956391095716111629998594075762507345430945523492775915790828078000453705320783486744734994213028476446922815870053311973844961
c2 = 20513108670823938405207629835395350087127287494963553421797351726233221750526355985253069487753150978011340115173042210284965521215128799369083065796356395285905154260709263197195828765397189267866348946188652752076472172155755940282615212228370367042435203584159326078238921502151083768908742480756781277358357734545694917591921150127540286087770229112383605858821811640935475859936319249757754722093551370392083736485637225052738864742947137890363135709796410008845576985297696922681043649916650599349320818901512835007050425460872675857974069927846620905981374869166202896905600343223640296138423898703137236463508
p = gcd(n1, n2)
if p > 1:
q1 = n1 // p
q2 = n2 // p
phi1 = (p - 1) * (q1 - 1)
phi2 = (p - 1) * (q2 - 1)
d1 = pow(e, -1, phi1)
d2 = pow(e, -1, phi2)
m1 = pow(c1, d1, n1)
m2 = pow(c2, d2, n2)
print("解密后的消息1:", m1)
print("解密后的消息2:", m2)
# 将 m1 和 m2 转换为字符串
try:
message1 = bytes.fromhex(hex(m1)[2:]).decode('utf-8')
message2 = bytes.fromhex(hex(m2)[2:]).decode('utf-8')
print("解密后的文本消息1:", message1)
print("解密后的文本消息2:", message2)
except:
print("...")
else:
print("...")
if __name__ == "__main__":
main()
得到结果
解密后的消息1: 584734024210053001694699533881960229862347256375
解密后的消息2: 6121411568964967526691207501160753713595005
解密后的文本消息1: flag{336BB5172ADE227
解密后的文本消息2: FE68BAA44FDA73F3B}
拼接得到完整flag
CRYPTO3 easycrypt
下载附件得到提图片
php加密函数,
加密函数的步骤如下:
1.反转输入字符串
2.对每个字符的ASCII码加1
3.将结果进行base64编码
4.再次反转字符串
5.应用ROT13加密
改成python如下
import base64
def decode(s):
# 1. 解除ROT13加密
def rot13(text):
return ''.join([chr((ord(c) - 97 + 13) % 26 + 97) if c.isalpha() and c.islower() else
chr((ord(c) - 65 + 13) % 26 + 65) if c.isalpha() and c.isupper() else c
for c in text])
o = rot13(s)
、
o = o[::-1]
、
o = base64.b64decode(o).decode('utf-8')
、
result = ''.join([chr(ord(c) - 1) for c in o])
、
return result[::-1]
encrypted = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"
decrypted = decode(encrypted)
print(decrypted)
得到flag
flag:
# MISC1 Forgeten password
hint 内存取证题
windows上安装[volatility3]
获取内存镜像的基本信息
根据hint小明总是喜欢password记录下来
,用editbox
显示出有关编辑控件的信息,得到密码password*&!@wxcq12
用密码直接交不对,那么应该是压缩包之类的密码了 查找压缩包并导出
用editbox
得到的密码解压压缩包拿到flag
MISC2 你是黑客吗
下载下来是一个压缩包,需要密码,根据题目描述,密码可能是100-1000 之间的素数数量
写出py代码
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
primes = [num for num in range(101, 1000) if is_prime(num)]
print("100到1000之间的所有质数:")
print(primes)
print(f"总共有 {len(primes)} 个质数")
得到 143
尝试之后不行
想 可能是 所有素数之和
添加代码
# 计算质数的和
prime_sum = sum(primes)
print(f"这些质数的和为: {prime_sum}")
得到结果
一张图片
使用hxd打开查看源代码,发现其中存在base64字符串,于是复制字符串使用base64编码得到一张二维码,扫码得到flag
Reverse2 NSCTF Rverse 400
下载得到Revesre03.exe,排查发现是一个pyinstaller打包的程序
⽤到了 PyInstaller Extractor 这个⼯具, 下载来后直接 执⾏ python pyinstxtractor.py Revesre03.exe
可以得到源⽂件。
打 开 Revesre03.exe_extracted/Revesre03 就能够得到源代码了
这是⼀段 Python 代码并嵌⼊了⼀段 C 的注释,
buf ⾥的 flag 并不是真正的 flag。
将 C 语⾔提取出来编译运⾏发现 encode 之后的 buf 和上⾯的 data 很像,尤其 是⾸尾是完全⼀样的,既然 encode(buf) ≈ data ,
那么 decode(data) ≈ buf ,所以猜测对 data 进⾏逆向解码就是真正的 flag。
data = \
"\x1c\x7a\x16\x77\x10\x2a\x51\x1f\x4c\x0f\x5b\x1d\x42\x2f
\x4b\x7e\x4a\x7a\x4a\x7b" +\
"\x49\x7f\x4a\x7f\x1e\x78\x4c\x75\x10\x28\x18\x2b\x48\x7e
\x46\x23\x12\x24\x11\x72" +\
"\x4b\x2e\x1b\x7e\x4f\x2b\x12\x76\x0b"
flag = ""
for i in range(len(data)-1):
flag += chr(ord(data[i]) ^ ord(data[i+1]))
print flag
Reverse3 Crackme
使用IDA打开
可以确认判断条件位于if语句中,决定是否调用MessageBoxA输出正确提示。接下来分析sub_401630函数:
函数主体部分首先使用srand生成随机数,然后令v4=rand[0]%10,再将v2和v3对应的某一位数值进行比对。
srand函数是随机数发生器的初始化函数,与rand()配合使用产生伪随机数序列。rand()函数通过系统给定的种子生成随机序列,而srand()可以改变种子值。
对于本题的逻辑,由于初始以10作为种子,rand[0]为0x47(71);以1作为种子,rand[0]为0x29(41),模10后都令v4=1,所以v4的值不会变化,始终为1。
确定v4后,判断逻辑变得清晰:a2的每一个值与v3+96的第n*10+1个值进行比对。
向上查找,发现:
这里有一个strcpy函数,将内存中的一串字符串赋值到v2+96。进一步分析可知,此处的v2+96就是v3+96。因此,只需将这个字符串每隔十个字符取出(直到取到320为止),就可以得到最终的flag
s = ";f1K3{c5:efl21t4;1t1zaxpim9}5+?gtux;=vc9v{v7+buhU{bT=-am2q}=fh[xk{y?xrqe{?}l5-sd2-Mo+:j{9=sY[dalvpx?z3{?no{[k5ll{zjsu5[kfla+r6Zg72o0skq6cGl5cw[=d?3v9q5-vkjSv{4sqtg=f0cz{+jurjfl[tb]lrfF1;2}udhb?0g8{om:T4dh;z:oz-Dn=m=ux;o[gs9{+zqx+sq-dsxctcvykUs2oddrt43pwv:f0;njkrb9los6g0{ih?rqantfx$sslqd:rvqixr;j{?o:sn+[i[yA11;gsmr8lm0?3};+iv+Tf:4Gtv2:-20upi0]7?77=;qzx{m-W;0vtueh]ko8d?=w:fbhd{E:;19?p=k:b+}doht6wpEq-z]2qbV1}dh416qw9:xm[;ed;:ecb-0:ni-s4u2kf6]2wn45amzjrun=ofkx-=hmgo-lz;j909=rmo7xcj4le0hxs[i]-vjl[?o12:sv4upio7ma1hRy7556+57krev:hLQ+1cx65z5v5];6n=[p83;n={zm{k2p"
flag=''
for i in range(len(s)//10):
flag+=s[i*10+1]
if(i*10==320):
break
print(flag)
比赛成绩
个人省排25,还算不错了