[BJDCTF 2nd]rsa1
- 题目链接(buu平台)
https://buuoj.cn/challenges#[BJDCTF 2nd]rsa1
- 题解
首先拿到题目靶机。nc交互获取得到题目数据
得到的条件有
- e
- p^2+q^2
- p-q
- c
明显是一个rsa加密。要去求解这个题目。因为求解rsa嘛。我们本质上肯定是想通过最基础的rsa解密去求解的。也就是我们要获取到私钥d以及公钥n。
这边我们通过去求解p和q的值。来求解rsa加密。
根据已知信息
假设
p^2+q^2=a
p-q=b
其中a、b已知
即求解二元二次方程
求解方程可以使用z3-solver进行求解
安装方法如下
找到官网
https://pypi.org/project/z3-solver/4.8.8.0/#files
下载对应系统的第三方库文件
例如我是windows系统,我下载的就是
z3_solver-4.8.8.0-py2.py3-none-win_amd64.whl
然后pip安装这个z3-solver库
pip install z3_solver-4.8.8.0-py2.py3-none-win_amd64.whl
然后求解出p和q的值进行一个基础的rsa解密就好了。
- 题解exp如下
import z3 import gmpy2 from Crypto.Util.number import * #公钥e e=11630623 #p^2+q^2 p2q2=159091823893455582874061921154612415267326476512949054956396980727282756099500423604620855106680518280081561541640137584218141965305223222299378169087637728170419037951685924289388185840842033127708318792414241966337535836497572877344724131756911624967860755193905135911797719211253029463146921655068409851682 #p-q p_q=-1028057512734526688756255253926193308887656904740633132866508165158161555923213681694346079000723418169221377228338798941679856716917764591264729224439880 #密文c c=c=16828607056351898528593346827961041518302251064718691085202163294074947863618526294699466675783765349214251854122505153854940088340991317516413847467861967618764774324129650766830916741676747137720500142976165361634620558308099053963312274170652756789297267286419176164695159543581037737967947118601658126996 #使用z3对二元二次方程进行求解 s=z3.Solver() #定义两个变量 p,q=z3.Ints("p q") #添加方程 s.add(p*p+q*q==p2q2) s.add(p-q==p_q) s.add(p>0) arr=[] #校验是否有解 if s.check()==z3.sat: arr=s.model() print(arr) #得到p,q q = 9418055170543903468662169278295577389409276234772590476185014016803075309886254123445652979884992724665244226628125328356664293030046148360676450649936611 p = 8389997657809376779905914024369384080521619330031957343318505851644913753963040441751306900884269306496022849399786529414984436313128383769411721425496731 #简单验证一下 assert(p*p+q*q==p2q2) assert(p-q==p_q) #rsa基础解密 n=p*q phi=(p-1)*(q-1) d=gmpy2.invert(e,phi) m=pow(c,d,n) flag=long_to_bytes(m) print(flag)
EasyProgram
- 题目链接(buu平台)
https://buuoj.cn/challenges#EasyProgram
拿到题目下载附件,得到两个文件
- file.txt
用python读入字节流,判断长度为38.长度为38我们知道flag{}加上中间32位md5值就是一个标准的flag.也就先判断file.txt存放的是flag的密文
- 附件.txt
一个加密算法,大概是类似伪代码之类的。也比较容易看懂
get buf unsign s[256]
get buf t[256]
we have key:whoami
we have flag:????????????????????????????????
for i:0 to 256
set s[i]:i
for i:0 to 256
set t[i]:key[(i)mod(key.lenth)]
for i:0 to 256
set j:(j+s[i]+t[i])mod(256)
swap:s[i],s[j]
for m:0 to 38
set i:(i + 1)mod(256)
set j:(j + S[i])mod(256)
swap:s[i],s[j]
set x:(s[i] + (s[j]mod(256))mod(256))
set flag[m]:flag[m]^s[x]
fprint flagx to file
简单的把代码理一下,改成python的实现
key="whoami"
flag="flag{test_test_test_test_test_test_te}"
s=[]
t=[]
flag_enc=""
for i in range(256):
s.append(i)
for i in range(256):
t.append(ord(key[i%len(key)]))
j=0
for i in range(256):
j=(j+s[i]+t[i])%256
tmp=s[i]
s[i]=s[j]
s[j]=tmp
i=0
j=0
for m in range(38):
i=(i+1)%256
j=(j+s[i])%256
tmp=s[i]
s[i]=s[j]
s[j]=tmp
x=(s[i]+s[j]%256)%256
flag_enc+=chr(ord(flag[m])^s[x])
print(flag_enc)
简单分析一下,就是一个最简单的流密码,可以把前面的操作看作生成了一个密钥流。这个密钥流明显是固定的(也就是说和加密的明文无关)。那就很简单,异或解密就可以了。
- 题解exp如下:
f=open("file.txt","rb") st=f.read() print(len(st)) flag_enc=st key="whoami" s=[] t=[] flag="" for i in range(256): s.append(i) for i in range(256): t.append(ord(key[i%len(key)])) j=0 for i in range(256): j=(j+s[i]+t[i])%256 tmp=s[i] s[i]=s[j] s[j]=tmp i=0 j=0 for m in range(38): i=(i+1)%256 j=(j+s[i])%256 tmp=s[i] s[i]=s[j] s[j]=tmp x=(s[i]+s[j]%256)%256 flag+=chr(flag_enc[m]^s[x]) print(flag)
[AFCTF2018]可怜的RSA
- 题目链接(buu平台)
https://buuoj.cn/challenges#[AFCTF2018]可怜的RSA
- 拿到附件:
- flag.enc
- public.key
就明显是拿到两个附件,一个是RSA加密的密钥文件,还有一个是flag加密后的密文的文件。
这边的话一种就是常规的用openssl,个人不太喜欢用。python能解决的问题我一般就python解决了。这边用到python的Crypto库,是做CTF密码学非常常用的一个库。
pip install pycrypto
安装好这个Crypto库
然后导入Crypto.PublicKey.RSA
用RSA模块的import_key函数将我们的publickey读入,拿到RSA加密的公钥n和e的具体参数
from Crypto.PublicKey import RSA
f=open("public.key","r")
key=RSA.import_key(f.read())
f.close()
e=key.e
n=key.n
然后发现n可以分解,直接在线网站http://factordb.com/把n给分解了,得到公钥n的两个因子。
然后就是常规的RSA求解私钥
这边因为flag.enc是RSA的PKCS1_OAEP加密得来的。所以我们这边也是给生成一个私钥文件。
在做到这边的时候,如何导出一个私钥文件。找了一下百度上的方法。都是先generate后给参数分别赋值的。但是我发现我并不行,试了一下python3和python2下的Crypto库都得到一个报错
Exception has occurred: AttributeError
can't set attribute
也就是现在无法通过这么直接赋值了。
这种情况的话,可以去看下python调用的Crypto库里面的RSA模块的一个底层的实现。
发现有一个construct函数,传入一个rsa_components参数,是一个元组型的数据,也就是tuple类型的,分别是(n,e,d,p,q)
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
rsa_components=(n,e,int(d),p,q)
arsa=RSA.construct(rsa_components)
arsa.exportKey()
然后导出的私钥,对加密后的密文,使用PKCS1_OAEP模块进行解密即可。
- 题解exp如下
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP f=open("public.key","r") key=RSA.import_key(f.read()) f.close() e=key.e n=key.n import base64 from Crypto.Util.number import * import gmpy2 p= 3133337 q=25478326064937419292200172136399497719081842914528228316455906211693118321971399936004729134841162974144246271486439695786036588117424611881955950996219646807378822278285638261582099108339438949573034101215141156156408742843820048066830863814362379885720395082318462850002901605689761876319151147352730090957556940842144299887394678743607766937828094478336401159449035878306853716216548374273462386508307367713112073004011383418967894930554067582453248981022011922883374442736848045920676341361871231787163441467533076890081721882179369168787287724769642665399992556052144845878600126283968890273067575342061776244939 print(p*q==n) f=open("flag.enc","r") c_base64=f.read().strip("\n") c_bytes=base64.b64decode(c_base64) c=bytes_to_long(c_bytes) phi=(p-1)*(q-1) d=gmpy2.invert(e,phi) rsa_components=(n,e,int(d),p,q) arsa=RSA.construct(rsa_components) rsakey = RSA.importKey(arsa.exportKey()) rsakey = PKCS1_OAEP.new(rsakey) decrypted = rsakey.decrypt(c_bytes) print(decrypted)
[AFCTF2018]BASE
- 题目链接(buu平台)
https://buuoj.cn/challenges#[AFCTF2018]BASE
- 附件
- flag_encode.txt
拿到附件是一个flag加密后的文本,其实是flag经过很多次base系列编码后的一个内容。文件有20+MB,文本编辑器发现是一行编码后的内容。
这题主要是三种编码,base64/base32/base16。base16也就是16进制。
就疯狂解码就行了。主要是考察一个脚本的编写吧,也只能这么理解。。
- 题解exp如下:
import base64 f=open("flag_encode.txt","r") c=f.readline() while True: ok=0 try: c=base64.b64decode(c).decode("ascii") ok=1 except: pass try: c=base64.b16decode(c).decode("ascii") ok=1 except: pass try: c=base64.b32decode(c).decode("ascii") ok=1 except: pass if not ok: print(c) break
[WUSTCTF2020]情书
- 题目链接(buu平台)
https://buuoj.cn/challenges#[WUSTCTF2020]情书
- 附件
- attachment.txt
拿到附件发现说明里面是RSA加密
并且给了密钥,密文。直接写脚本解就完事了。
接出来的内容为字母表的索引,找到对应的字母即可
- 题解exp如下:
en=[156,821,1616,41,140,2130,1616,793] import string table=string.ascii_lowercase print(table) for i in en: print(table[pow(i,937,2537)],end="")
[NPUCTF2020]Classical Cipher
- 题目链接(buu平台)
https://buuoj.cn/challenges#[NPUCTF2020]Classical Cipher
- 附件
- key.txt
- flag.zip
flag.zip为加密的zip文件,zip密码为key.txt中
因为这边有一组明密文的对应关系,即key→pvb,古典密码学思想直接词频分析。
使用词频分析网站:https://www.quipqiup.com/
得到结果:the_key_is_atrash
尝试用这个去解密发现密码错误。
然后仔细分析一下这个词频分析结果。发现有atbash,这个词的话就比较熟悉,古典密码里面经典的单表替换密码。
其实压缩包密码为the_key_is_atbash。主要是因为词频分析的话atrash更符合表达。
直接atbash解密即可
解开压缩包拿到图片
猪圈密码的话是比较常见的一种编码了。可以百度一下,这边要注意一点,这个猪圈密码和CTFwiki上面给出的那个表不同。对应关系参照的是这个表:
然后还有一些动物啥的,其实是象形文字。。。怎么说呢,勉勉强强算是理解成一种编码吧。这边对应的编码表也是给大家找来了。
这边对应下两张表去解出明文即可。
[网鼎杯 2020 青龙组]you_raise_me_up
- 题目链接(buu平台)
https://buuoj.cn/challenges#[网鼎杯 2020 青龙组]you_raise_me_up
- 附件
- you_raise_me_up.py
附件就是一个加密脚本,然后输出的话也是直接注释在了脚本里面。
其实乍一看你会发现他和RSA加密很像,最后的加密过程为。
c = pow(m, bytes_to_long(flag), n)
我们知道RSA加密就是令明文为m,取公钥e和n,密文c=pow(m,e,n)
这边的一个明显区别为,可以理解为flag明文作为RSA加密里面的公钥e进行的求解。
这个在密码学里面是基于离散对数的一种加密,我们在求解明文的时候,也就相当于是求解基于同余运算和原根的一种对数运算。
求解这种问题的话我们用python的sympy模块的discrete_log函数进行求解就可以了。discrete_log(n,c,m)
- 题解exp如下:
m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075 c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499 n = 2 ** 512 import sympy from Crypto.Util.number import * flag=sympy.discrete_log(n,c,m) print(long_to_bytes(flag))
[ACTF新生赛2020]crypto-aes
- 题目链接(buu平台)
https://buuoj.cn/challenges#[ACTF新生赛2020]crypto-aes
- 附件
- aes.py
- output
分析附件,发现aes.py是一个简单的aes cbc模式的加密脚本。
def main():
key=os.urandom(2)*16
iv=os.urandom(16)
print(bytes_to_long(key)^bytes_to_long(iv))
aes=AES.new(key,AES.MODE_CBC,iv)
enc_flag = aes.encrypt(FLAG)
print(enc_flag)
if __name__=="__main__":
main()
很显然的是,key和iv为两个随机比特流。但是特点很明显。
其中key是长度为两个字节的比特流重复了16次。iv就是一个长度为16字节的比特流
故这边,key的长度为32字节,iv的长度为16字节
然后给了我们key和iv异或的输出结果
这边易得到一个结论,key的低16字节与iv的16字节异或,而key的高16字节就保留了,可以看作高16字节的每一位都是与0异或,而与0异或结果就是它本身。
这边我们将output文件中得到的key与iv异或结果的10进制值,转换成16进制值。我们知道16进制的每两位表示的是一个字节。这边可以看到输出结果的高位都是c981的一个重复。即可得key中重复的两字节的16进制分别是c9和81,如此我们也就得到了key,再异或得到iv进行aes基础解密即可。
- 题解exp如下:
import os from Crypto.Util.number import * from Crypto.Cipher import AES xor_re=91144196586662942563895769614300232343026691029427747065707381728622849079757 key=b'\xc9\x81'*16 print(key) key_long=bytes_to_long(key) iv=(long_to_bytes(xor_re^key_long)) print(iv) c=b'\x8c-\xcd\xde\xa7\xe9\x7f.b\x8aKs\xf1\xba\xc75\xc4d\x13\x07\xac\xa4&\xd6\x91\xfe\xf3\x14\x10|\xf8p' aes=AES.new(key,AES.MODE_CBC,iv) flag=aes.decrypt(c) print(flag)
[INSHack2017]rsa16m
- 题目链接(buu平台)
https://buuoj.cn/challenges#[INSHack2017]rsa16m
- 附件
- rsa_16m
附件rsa_16m是一个7+MB的文件,里面主要的一个数据为RSA加密体系中的n,e,c。
可以发现的是n极大,e虽然也挺大的,为0x10001。但是这边明文flag的e次方还是小于n的。故这一题直接用rsa里面的小明文攻击即可。
直接对密文c开e次方根
- 题解exp如下:
f=open("rsa_16m","r") f.readline() c=int(f.readline().strip("\n").split(" = ")[1],16) e=0x10001 import gmpy2 from Crypto.Util.number import * flag=long_to_bytes(gmpy2.iroot(c,e)[0]) print(flag)
[XNUCA2018]Warmup
- 题目链接(buu平台)
https://buuoj.cn/challenges#[XNUCA2018]Warmup
- 附件
- Buggy_Server.py
- sniffed.pcapng
简单分析一下Buggy_Server.py脚本,是一个模拟发送消息的脚本,使用的是rsa加密,通过传入user将flag消息进行rsa加密发送给user,并抓取所有消息的一个流量。
直接对流量包进行一个分析,追踪一下TCP流,可以发现
题目给出的流量包的内容,即发送给user的rsa加密数据。
这边发现,发送给Alice和Carol这两个用户,使用的公钥n是一样的。那就是一个rsa里面经典的共模攻击。
- 题解exp如下:
import sys import binascii sys.setrecursionlimit(1000000) def egcd(a, b): if a == 0: return (b, 0, 1) else: g, y, x = egcd(b % a, a) return (g, x - (b // a) * y, y) def modinv(a, m): g, x, y = egcd(a, m) if g != 1: raise Exception('modular inverse does not exist') else: return x % m c1=22917655888781915689291442748409371798632133107968171254672911561608350738343707972881819762532175014157796940212073777351362314385074785400758102594348355578275080626269137543136225022579321107199602856290254696227966436244618441350564667872879196269074433751811632437228139470723203848006803856868237706401868436321225656126491701750534688966280578771996021459620472731406728379628286405214996461164892486734170662556518782043881759918394674517409304629842710180023814702447187081112856416034885511215626693534876901484105593275741829434329109239483368867518384522955176807332437540578688867077569728548513876841471 n=25118186052801903419891574512806521370646053661385577314262283167479853375867074736882903917202574957661470179148882538361560784362740207649620536746860883395110443930778132343642295247749797041449601967434690280754279589691669366595486824752597992245067619256368446164574344449914827664991591873150416287647528776014468498025993455819767004213726389160036077170973994848480739499052481386539293425983093644799960322581437734560001018025823047877932105216362961838959964371333287407071080250979421489210165485908404019927393053325809061787560294489911475978342741920115134298253806238766543518220987363050115050813263 e1=7669 c2=20494665879116666159961016125949070097530413770391893858215547229071116025581822729798313796823204861624912909030975450742122802775879194445232064367771036011021366123393917354134849911675307877324103834871288513274457941036453477034798647182106422619504345055259543675752998330786906376830335403339610903547255965127196315113331300512641046933227008101401416026809256813221480604662012101542846479052832128788279031727880750642499329041780372405567816904384164559191879422615238580181357183882111249939492668328771614509476229785062819586796660370798030562805224704497570446844131650030075004901216141893420140140568 e2=6947 s = egcd(e1, e2) s1 = s[1] s2 = s[2] if s1<0: s1 = - s1 c1 = modinv(c1, n) elif s2<0: s2 = - s2 c2 = modinv(c2, n) m=(pow(c1,s1,n)*pow(c2,s2,n)) % n print(m) print (binascii.unhexlify(hex(m)[2:].strip("L")))
[b01lers2020]safety_in_numbers
- 题目链接(buu平台)
https://buuoj.cn/challenges#[b01lers2020]safety_in_numbers
- 附件
- enc.py
- flag.enc
- pubkey.pem
这边的话enc.py里面要注意一个点,他从int转成bytes和bytes转int都是用的小端模式也就是byteorder = ‘little’,这个和我们正常的一个转换刚好相反的。
然后可以发现是pubkey.pem极大,有1.6MB,这边如果是使用RSA.importKey是无法取出他的公钥n,e的。因为根本无法导入。但是我们其实知道公钥文件的格式,
e其实就在base64编码的公钥文件的尾部
import base64
key_end_base64="l8UvtaFCpNsgheCRz1j+HD9cHH05ozrbHMe/rtEUQa6fmQcAJbDNBXZV+yabO1aSKwVm5ZgHKQIDAQAB"
key=base64.b64decode(key_end_base64)
print(hex(bytes_to_long(key)))
得到结果如下
明显最后的16进制值为0x10001,这也是rsa中最常用的一个公钥e。
因为n极大,这题也是直接小明文攻击求解。
- 题解exp如下:
from Crypto.Util.number import * import base64 import gmpy2 key_end_base64="l8UvtaFCpNsgheCRz1j+HD9cHH05ozrbHMe/rtEUQa6fmQcAJbDNBXZV+yabO1aSKwVm5ZgHKQIDAQAB" key=base64.b64decode(key_end_base64) print(hex(bytes_to_long(key))) f=open("flag.enc","rb") c_bytes=f.read() c=int.from_bytes(c_bytes,byteorder="little") m=gmpy2.iroot(c,0x10001)[0] flag=long_to_bytes(m)[::-1] print(flag)
[AFCTF2018]MyOwnCBC
- 题目链接(buu平台)
https://buuoj.cn/challenges#[AFCTF2018]MyOwnCBC
- 附件
- MyOwnCBC.py
- flag_cipher
def MyOwnCBC(key, plain): if len(key)!=32: return "error!" cipher_txt = b"" cipher_arr = [] cipher = AES.new(key, AES.MODE_ECB, "") plain = [plain[i:i+32] for i in range(0, len(plain), 32)] print (plain) cipher_arr.append(cipher.encrypt(plain[0])) cipher_txt += cipher_arr[0] for i in range(1, len(plain)): cipher = AES.new(cipher_arr[i-1], AES.MODE_ECB, "") cipher_arr.append(cipher.encrypt(plain[i])) cipher_txt += cipher_arr[i] return cipher_txt
简单的对MyOwnCBC.py脚本进行分析,可以发现,其实就是ECB模式下的AES,然后将每个分组单独进行了AES ECB加密,可以看到的是每一组AES加密的key为上一组加密结果的密文。
出题人设计这个题目的意图应该是想带大家了解一下AES CBC模式,用ECB模式进行一个大概的模拟(当然不是这个原理)。主要是想表达CBC模式下会把上一轮的加密影响扩散到下一轮的意思吧。
那解密也很简单,因为key其实就是每组加密后的密文嘛,直接AES ECB模式下解密即可。
- 题解exp如下:
from Crypto.Cipher import AES from Crypto.Random import random from Crypto.Util.number import long_to_bytes f=open("flag_cipher","rb") st=f.read() print(len(st)) def MyOwnCBC(key, plain): cipher_txt = b"" cipher = AES.new(key, AES.MODE_ECB) cipher_txt=cipher.decrypt(plain) return cipher_txt #for i in range(len(st)//32): flag="" for i in range(1,10): plain=MyOwnCBC(st[(52-i-1)*32:(52-i)*32],st[(52-i)*32:(53-i)*32]) flag=plain.decode()+flag print(flag)
[RoarCTF2019]RSA
- 题目链接(buu平台)
https://buuoj.cn/challenges#[RoarCTF2019]RSA
- 附件
- attachment
题面如下:
A=(((y%x)**5)%(x%y))**2019+y**316+(y+1)/x
p=next_prime(z*x*y)
q=next_prime(z)
A =
n =
c =
这一题我们发现n直接可以分解。
这一点我也很费解。。因为RoarCTF当时也有参与出题和测题。明明不应该出现这个问题。这个factordb的网站有收录就很离谱。
这边介绍一下预期解。
我们首先看到
A=(((y%x)**5)%(x%y))**2019+y**316+(y+1)/x
这边可以发现,其实这个方程里面最大的一项是(((y%x)5)%(x%y))2019
这边之前底数大于等于2,那么这一项直接就大于A了。所以这一项必然是0或者1
其次就是y316了。发现当y为84的时候y316就已经大于A了。所以得到y肯定是小于84的
然后最后一项的结果肯定也很小。所以这边基本就确定了y为83了。然后爆破一下x,得到x为2
到这里我们就得到了x*y的一个值。然后我们知道p和q共有一个大因子z,虽然最后是取了一个next_prime,但是我们可以先得到一个大概的值
得到一个z的大概值
xy=x*y
zz_near=n//xy
z_near=gmpy2.iroot(zz_near,2)[0]
然后写个二分法去求解一下pq的值
low=0
hei=10000000
while low<hei:
mid=(low+hei)//2
p=gmpy2.next_prime((z_near-mid)*x*y)
q=gmpy2.next_prime((z_near-mid))
if p*q-n>0:
low=mid+1
elif p*q-n<0:
hei=mid-1
else:
break
然后基础的RSA解密即可
- 题解exp如下:
import gmpy2 from Crypto.Util.number import * y=0 A=2683349182678714524247469512793476009861014781004924905484127480308161377768192868061561886577048646432382128960881487463427414176114486885830693959404989743229103516924432512724195654425703453612710310587164417035878308390676612592848750287387318129424195208623440294647817367740878211949147526287091298307480502897462279102572556822231669438279317474828479089719046386411971105448723910594710418093977044179949800373224354729179833393219827789389078869290217569511230868967647963089430594258815146362187250855166897553056073744582946148472068334167445499314471518357535261186318756327890016183228412253724 n = 117930806043507374325982291823027285148807239117987369609583515353889814856088099671454394340816761242974462268435911765045576377767711593100416932019831889059333166946263184861287975722954992219766493089630810876984781113645362450398009234556085330943125568377741065242183073882558834603430862598066786475299918395341014877416901185392905676043795425126968745185649565106322336954427505104906770493155723995382318346714944184577894150229037758434597242564815299174950147754426950251419204917376517360505024549691723683358170823416757973059354784142601436519500811159036795034676360028928301979780528294114933347127 c = 41971850275428383625653350824107291609587853887037624239544762751558838294718672159979929266922528917912189124713273673948051464226519605803745171340724343705832198554680196798623263806617998072496026019940476324971696928551159371970207365741517064295956376809297272541800647747885170905737868568000101029143923792003486793278197051326716680212726111099439262589341050943913401067673851885114314709706016622157285023272496793595281054074260451116213815934843317894898883215362289599366101018081513215120728297131352439066930452281829446586562062242527329672575620261776042653626411730955819001674118193293313612128 ''' for i in range(1000): if i**316>A: print(i) break ''' y=83 x=0 ''' for x in range(1,1000): if (((y%x)**5)%(x%y))**2019+y**316+(y+1)//x==A: print(x) break ''' x=2 xy=x*y zz_near=n//xy z_near=gmpy2.iroot(zz_near,2)[0] low=0 hei=10000000 while low<hei: mid=(low+hei)//2 p=gmpy2.next_prime((z_near-mid)*x*y) q=gmpy2.next_prime((z_near-mid)) if p*q-n>0: low=mid+1 elif p*q-n<0: hei=mid-1 else: break print(p*q==n) phi=(p-1)*(q-1) e=0x10001 d=gmpy2.invert(e,phi) m=pow(c,d,n) flag=long_to_bytes(m) print(flag)
[AFCTF2018]One Secret, Two encryption
- 题目链接(buu平台)
https://buuoj.cn/challenges#[AFCTF2018]One Secret, Two encryption
- 附件
- public1.pub
- public2.pub
- flag_encry1
- flag_encry2
给了一份题面
一份秘密发送给两个人不太好吧,那我各自加密一次好啦~~~
素数生成好慢呀
偷个懒也……不会有问题的吧?
这边首先把两份公钥文件的n,e取出来看了一下
from Crypto.PublicKey import RSA
import gmpy2
from Crypto.Util.number import *
f=open("public1.pub","r")
rsa1=RSA.import_key(f.read())
n1=rsa1.n
e1=rsa1.e
f.close()
f=open("public2.pub","r")
rsa2=RSA.import_key(f.read())
n2=rsa2.n
e2=rsa2.e
f.close()
print(n1,e1)
print(n2,e2)
测试发现n1 n2有公约数。这边也是印证了题面给的懒得生成素数,所以共用了其中一个素数。这边直接gcd求解公约数即可。
然后分解出p q进行一个基础的RSA解密
- 题解exp如下:
from Crypto.PublicKey import RSA import gmpy2 from Crypto.Util.number import * f=open("public1.pub","r") rsa1=RSA.import_key(f.read()) n1=rsa1.n e1=rsa1.e f.close() f=open("public2.pub","r") rsa2=RSA.import_key(f.read()) n2=rsa2.n e2=rsa2.e f.close() #print(n1,e1) #print(n2,e2) p=gmpy2.gcd(n1,n2) q=n2//p assert(p*q==n2) phi=(p-1)*(q-1) d=gmpy2.invert(e2,phi) c_bytes=open("flag_encry2","rb").read() c=bytes_to_long(c_bytes) m=pow(c,d,n2) flag=long_to_bytes(m) print(flag)
[INSHack2019]Yet Another RSA Challenge – Part 1
- 题目链接(buu平台)
https://buuoj.cn/challenges#[INSHack2019]Yet Another RSA Challenge – Part 1
- 附件
- yarsac.py
- output.txt
题面很清晰,就是一个RSA加密,然后给了公钥n的其中有一个因子p,但是p是16进制表示的,最后输出的时候把9F替换成了FC。那么我们在给的output.txt文件中得到p的时候,其中的FC的位置就有可能为9F,亦有可能为FC。这边写个脚本爆破一下求解即可。
- 题解exp如下:
import gmpy2 from Crypto.Util.number import * n=719579745653303119025873098043848913976880838286635817351790189702008424828505522253331968992725441130409959387942238566082746772468987336980704680915524591881919460709921709513741059003955050088052599067720107149755856317364317707629467090624585752920523062378696431510814381603360130752588995217840721808871896469275562085215852034302374902524921137398710508865248881286824902780186249148613287250056380811479959269915786545911048030947364841177976623684660771594747297272818410589981294227084173316280447729440036251406684111603371364957690353449585185893322538541593242187738587675489180722498945337715511212885934126635221601469699184812336984707723198731876940991485904637481371763302337637617744175461566445514603405016576604569057507997291470369704260553992902776099599438704680775883984720946337235834374667842758010444010254965664863296455406931885650448386682827401907759661117637294838753325610213809162253020362015045242003388829769019579522792182295457962911430276020610658073659629786668639126004851910536565721128484604554703970965744790413684836096724064390486888113608024265771815004188203124405817878645103282802994701531113849607969243815078720289912255827700390198089699808626116357304202660642601149742427766381 cipher=596380963583874022971492302071822444225514552231574984926542429117396590795270181084030717066220888052607057994262255729890598322976783889090993129161030148064314476199052180347747135088933481343974996843632511300255010825580875930722684714290535684951679115573751200980708359500292172387447570080875531002842462002727646367063816531958020271149645805755077133231395881833164790825731218786554806777097126212126561056170733032553159740167058242065879953688453169613384659653035659118823444582576657499974059388261153064772228570460351169216103620379299362366574826080703907036316546232196313193923841110510170689800892941998845140534954264505413254429240789223724066502818922164419890197058252325607667959185100118251170368909192832882776642565026481260424714348087206462283972676596101498123547647078981435969530082351104111747783346230914935599764345176602456069568419879060577771404946743580809330315332836749661503035076868102720709045692483171306425207758972682717326821412843569770615848397477633761506670219845039890098105484693890695897858251238713238301401843678654564558196040100908796513657968507381392735855990706254646471937809011610992016368630851454275478216664521360246605400986428230407975530880206404171034278692756 e=65537 guess=["9F","FC"] p_=0 for a in guess: for b in guess: for c in guess: for d in guess: p="DCC5A0BD3A1"+a+"0BEB0DA1C2E8CF6B474481B7C12849B76E03C4C946724DB577D2825D6AA193DB559BC9DBABE1DDE8B5E7805E48749EF002F622F7CDBD7853B200E2A027E87E331A"+b+"FD066ED9900F1E5F5E5196A451A6F9E329EB889D773F08E5FBF45AACB818FD186DD74626180294DCC31805A88D1B71DE5BFEF3ED01F12678D906A833A78EDCE9BDAF22BBE45C0BFB7A82AFE42C1C3B8581C83BF43DFE31BFD81527E507686956458905CC9A660604552A060109DC81D01F229A264AB67C6D7168721AB36DE769CEAFB97F238050193EC942078DDF5329A387F46253A4411A9C8BB71F9AEB11AC9623E41C14"+c+"D2739D76E69283E57DDB11"+d+"531B4611EE3" p=int(p,16) q=n//p if (p*q==n): p_=p p=p_ q=n//p print(p*q==n) phi=(p-1)*(q-1) d=gmpy2.invert(e,phi) m=pow(cipher,d,n) flag=long_to_bytes(m) print(flag)
[GUET-CTF2019]NO SOS
- 题目链接(buu平台)
https://buuoj.cn/challenges#[GUET-CTF2019]NO SOS
- 附件:
- attachment.txt
首先发现一个很类似摩斯电码的东西。但是题目也写了no sos,所以应该不是莫斯电码。并且也发现没有间隔。与之类似的有可能是2进制的表示或者培根密码。这边将.转为A将—转为B后发现位数刚好为5的倍数。
培根密码解密得到flag
[UTCTF2020]basic-crypto
- 题目链接(buu平台)
https://buuoj.cn/challenges#[UTCTF2020]basic-crypto
- 附件:
- attachment.txt
这题附件里面表示的就很明显,每一组都是8位二进制。直接转ascii字符即可。
- 题解exp如下:
f=open("attachment.txt","r") arr=f.read().split(" ") re="" for i in arr: re+=chr(int(i,2)) print(re)
[ACTF新生赛2020]crypto-rsa3
- 题目链接(buu平台)
https://buuoj.cn/challenges#[ACTF新生赛2020]crypto-rsa3
- 附件:
- rsa3.py
- output.txt
可以发现就是最基础的RSA加密,其中p q为相邻的素数。直接yafu分解即可。
然后基础RSA解密即可
题解exp如下:
n=177606504836499246970959030226871608885969321778211051080524634084516973331441644993898029573612290095853069264036530459253652875586267946877831055147546910227100566496658148381834683037366134553848011903251252726474047661274223137727688689535823533046778793131902143444408735610821167838717488859902242863683
c=1457390378511382354771000540945361168984775052693073641682375071407490851289703070905749525830483035988737117653971428424612332020925926617395558868160380601912498299922825914229510166957910451841730028919883807634489834128830801407228447221775264711349928156290102782374379406719292116047581560530382210049
e=65537
p = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179293
q = 13326909050357447643526585836833969378078147057723054701432842192988717649385731430095055622303549577233495793715580004801634268505725255565021519817179231
from Crypto.Util.number import *
import gmpy2
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
flag=long_to_bytes(m)
print(flag)
[MRCTF2020]babyRSA
- 题目链接(buu平台)
https://buuoj.cn/challenges#[MRCTF2020]babyRSA
- 附件:
- baby_RSA.py
题目脚本比较长,一步一步分析。
if __name__ == "__main__":
_E = base
_P = gen_p()
_Q = gen_q()
assert (gcd(_E, (_P - 1) * (_Q - 1)) == 1)
_M = bytes_to_long(flag)
_C = pow(_M, _E, _P * _Q)
print("Ciphertext = ", _C)
首先,在主函数里面可以看到。其实这就是一个RSA加密。无非是_P和_Q都是带入了两个函数里面求解的。
def gen_q():
sub_Q = getPrime(1024)
Q_1 = getPrime(1024)
Q_2 = getPrime(1024)
Q = sub_Q ** Q_2 % Q_1
print("Q_1: ", Q_1)
print("Q_2: ", Q_2)
print("sub_Q: ", sub_Q)
return sympy.nextprime(Q)
_Q这个参数的话可以看到我们已知Q_1、Q_2、sub_Q就可以直接求解。
import sympy
import gmpy2
from Crypto.Util.number import *
Q_1=103766439849465588084625049495793857634556517064563488433148224524638105971161051763127718438062862548184814747601299494052813662851459740127499557785398714481909461631996020048315790167967699932967974484481209879664173009585231469785141628982021847883945871201430155071257803163523612863113967495969578605521
Q_2=151010734276916939790591461278981486442548035032350797306496105136358723586953123484087860176438629843688462671681777513652947555325607414858514566053513243083627810686084890261120641161987614435114887565491866120507844566210561620503961205851409386041194326728437073995372322433035153519757017396063066469743
sub_Q=168992529793593315757895995101430241994953638330919314800130536809801824971112039572562389449584350643924391984800978193707795909956472992631004290479273525116959461856227262232600089176950810729475058260332177626961286009876630340945093629959302803189668904123890991069113826241497783666995751391361028949651
Q=pow(sub_Q,Q_2, Q_1)
q=sympy.nextprime(Q)
print(q)
然后看到gen_p()这个函数
def gen_p():
P = [0 for i in range(17)]
P[0] = getPrime(128)
for i in range(1, 17):
P[i] = sympy.nextprime(P[i-1])
print("P_p :", P[9])
n = 1
for i in range(17):
n *= P[i]
p = getPrime(1024)
factor = pow(p, base, n)
print("P_factor :", factor)
return sympy.nextprime(p)
这边我们要求解p,其实就相当于求解一个RSA。n是由17个连续的质数作为因子的。然后我们得到了其中的第十个也就是下标为9的因子。那么我们通过sympy.prevprime和sympy.nextprime去求解得到所有的质数进行RSA基础解密得到p,然后取p的下一个质数作为_P即可。
- 题解exp如下:
import sympy import gmpy2 from Crypto.Util.number import * Q_1=103766439849465588084625049495793857634556517064563488433148224524638105971161051763127718438062862548184814747601299494052813662851459740127499557785398714481909461631996020048315790167967699932967974484481209879664173009585231469785141628982021847883945871201430155071257803163523612863113967495969578605521 Q_2=151010734276916939790591461278981486442548035032350797306496105136358723586953123484087860176438629843688462671681777513652947555325607414858514566053513243083627810686084890261120641161987614435114887565491866120507844566210561620503961205851409386041194326728437073995372322433035153519757017396063066469743 sub_Q=168992529793593315757895995101430241994953638330919314800130536809801824971112039572562389449584350643924391984800978193707795909956472992631004290479273525116959461856227262232600089176950810729475058260332177626961286009876630340945093629959302803189668904123890991069113826241497783666995751391361028949651 Q=pow(sub_Q,Q_2, Q_1) q=sympy.nextprime(Q) print(q) P_p=206027926847308612719677572554991143421 P=[] for i in range(9): P_p=sympy.prevprime(P_p) P.append(P_p) P=P[::-1] P_p=206027926847308612719677572554991143421 P.append(P_p) for i in range(9): P_p=sympy.nextprime(P_p) P.append(P_p) n_p=1 for i in range(17): n_p *= P[i] phi_p=1 for i in range(17): phi_p *= (P[i]-1) P_factor=213671742765908980787116579976289600595864704574134469173111790965233629909513884704158446946409910475727584342641848597858942209151114627306286393390259700239698869487469080881267182803062488043469138252786381822646126962323295676431679988602406971858136496624861228526070581338082202663895710929460596143281673761666804565161435963957655012011051936180536581488499059517946308650135300428672486819645279969693519039407892941672784362868653243632727928279698588177694171797254644864554162848696210763681197279758130811723700154618280764123396312330032986093579531909363210692564988076206283296967165522152288770019720928264542910922693728918198338839 base = 65537 d_p=gmpy2.invert(base,phi_p) p=sympy.nextprime(pow(P_factor,d_p,n_p)) Ciphertext = 1709187240516367141460862187749451047644094885791761673574674330840842792189795049968394122216854491757922647656430908587059997070488674220330847871811836724541907666983042376216411561826640060734307013458794925025684062804589439843027290282034999617915124231838524593607080377300985152179828199569474241678651559771763395596697140206072537688129790126472053987391538280007082203006348029125729650207661362371936196789562658458778312533505938858959644541233578654340925901963957980047639114170033936570060250438906130591377904182111622236567507022711176457301476543461600524993045300728432815672077399879668276471832 phi=(p-1)*(q-1) d=gmpy2.invert(base,phi) m=pow(Ciphertext,d,p*q) flag=long_to_bytes(m) print(flag)
[WUSTCTF2020]dp_leaking_1s_very_d@angerous
- 题目链接(buu平台)
https://buuoj.cn/challenges#[WUSTCTF2020]dp_leaking_1s_very_d@angerous - 附件:
- attachment
题意很明显,是dp泄露。
dp=d%(p-1)
这种参数是为了让解密的时候更快速产生的
- 题解exp如下:
import gmpy2 import rsa import binascii p=0 e=65537 n = 156808343598578774957375696815188980682166740609302831099696492068246337198792510898818496239166339015207305102101431634283168544492984586566799996471150252382144148257236707247267506165670877506370253127695314163987084076462560095456635833650720606337852199362362120808707925913897956527780930423574343287847 c = 108542078809057774666748066235473292495343753790443966020636060807418393737258696352569345621488958094856305865603100885838672591764072157183336139243588435583104423268921439473113244493821692560960443688048994557463526099985303667243623711454841573922233051289561865599722004107134302070301237345400354257869 dp = 734763139918837027274765680404546851353356952885439663987181004382601658386317353877499122276686150509151221546249750373865024485652349719427182780275825 temp=dp*e for i in range(1,e) : if (temp-1)%i==0: x=(temp-1)//i+1 y=n%x if y==0: p=x break q=n//p d=gmpy2.invert(e,(p-1)*(q-1)) key=rsa.PrivateKey(n,e,d,p,q) m=pow(c,d,n) print(binascii.unhexlify(hex(m)[2:]))