当前位置: 代码迷 >> 综合 >> BUUCTF 打卡6
  详细解决方案

BUUCTF 打卡6

热度:39   发布时间:2023-11-22 18:38:08.0

1.四面八方

刚开始看还以为是维吉尼亚密码,但解不出合适的flag。看了他人的wp才知道是四方密码。

  • 四方密码
    1.介绍
    四方密码用4个5×5的矩阵来加密。每个矩阵都有25个字母(通常会取消Q或将I,J视作同一样,或改进为6×6的矩阵,加入10个数字)
    2.原理
    1)首先选择两个英文字作密匙,例如example和keyword。对于每一个密匙,将重复出现的字母去除,即example要转成exampl,然后将每个字母顺序放入矩阵,再将余下的字母顺序放入矩阵,便得出加密矩阵。
    2)将这两个加密矩阵放在右上角和左下角,余下的两个角放a到z顺序的矩阵: [1]
    3.加密的步骤:
    两个字母一组地分开讯息:(例如hello world变成he ll ow or ld);
    找出第一个字母在左上角矩阵的位置;
    同样道理,找第二个字母在右下角矩阵的位置;
    找右上角矩阵中,和第一个字母同行,第二个字母同列的字母;
    找左下角矩阵中,和第一个字母同列,第二个字母同行的字母;
    得到的这两个字母就是加密过的讯息。
    he lp me ob iw an ke no bi的加密结果:FY NF NE HW BX AF FO KH MD

盗取大佬的图:
在这里插入图片描述

当然这个也有专门解密的网站:四方密码解密

在这里插入图片描述
得到了ypuogaodsuccessfum,貌似有一些英文单词的影子,successfum~successful。不过还是还是有点难猜的。看了大佬的wp,是将ypuogaodsuccessfum分成了ypuog aod successfum。理解倒是不难,但有点难想。
在这里插入图片描述
可恶到最后还要把空格去掉。

2.[QCTF2018]Xman-RSA

这个加密脚本原来被加密了啊!头一次碰到这种题。
在这里插入图片描述
不过解出来的还是有错误的地方,需要自己改(有的可以根据代码意思改正)。
改正后的代码如下:

from gmpy2 import is_prime
from os import urandom
import base64def bytes_to_num(b):return int(b.encode('hex'), 16)
def num_to_bytes(n):b = hex(n)[2:-1]#b = '0' + b if len(b)%2 == 1 else bif len(b)%2 == 1:b = '0' + b#使len(b)%2==0 return b.decode('hex')
def get_a_prime(l):random_seed = urandom(l)num = bytes_to_num(random_seed)while True:if is_prime(num):breaknum+=1return num
def encrypt(s, e, n):p = bytes_to_num(s)p = pow(p, e, n)return num_to_bytes(p).encode('hex')def separate(n):p = n % 4t = (p*p) % 4return t == 1#return True or False n*n%4f = open('flag.txt', 'r')
flag = f.read()msg1 = ""
msg2 = ""
for i in range(len(flag)):if separate(i):msg2 += flag[i]else:msg1 += flag[i]p1 = get_a_prime(128)
p2 = get_a_prime(128)
p3 = get_a_prime(128)
n1 = p1*p2
n2 = p1*p3
e = 0x1001
c1 = encrypt(msg1, e, n1)
c2 = encrypt(msg2, e, n2)
print(c1)
print(c2)
e1 = 0x1001
e2 = 0x101
p4 = get_a_prime(128)
p5 = get_a_prime(128)
n3 = p4*p5
c1 = num_to_bytes(pow(n1, e1, n3)).encode('hex')
c2 = num_to_bytes(pow(n1, e2, n3)).encode('hex')
print(c1)
print(c2)print(base64.b64encode(num_to_bytes(n2)))
print(base64.b64encode(num_to_bytes(n3)))

分析可知,我们可以先求出n2,n3。再根据第二个c1,c2,通过共模攻击求出n1。之后进行大数分解,求出p1,p2,p3,进而求出d1,d2,再求出msg1,msg2。最后根据代码给出的循环,求出flag。

我试了一下,发现这个代码要在py2中运行,但是py2中的pow()报了个错

n1 = (pow(c11,s,n3)*pow(c22,t,n3))%n3 TypeError: pow() 2nd argument cannot be negative when 3rd argument specified

但py3中可以,所以我写这个的时候两个版本都用了,有点混乱!(一开始看那些代码有些写法跟py3不一样,有点生疏,不好改它的代码。)

现在想想好像它写的那两个子程序不就是long_to_bytes和bytes_to_long吗!把代码改了,就全在py3中运行了。

import gmpy2,base64
from Crypto.Util.number import *e = int('0x1001',16)
c1 = int('1240198b148089290e375b999569f0d53c32d356b2e95f5acee070f016b3bef243d0b5e46d9ad7aa7dfe2f21bda920d0ac7ce7b1e48f22b2de410c6f391ce7c4347c65ffc9704ecb3068005e9f35cbbb7b27e0f7a18f4f42ae572d77aaa3ee189418d6a07bab7d93beaa365c98349d8599eb68d21313795f380f05f5b3dfdc6272635ede1f83d308c0fdb2baf444b9ee138132d0d532c3c7e60efb25b9bf9cb62dba9833aa3706344229bd6045f0877661a073b6deef2763452d0ad7ab3404ba494b93fd6dfdf4c28e4fe83a72884a99ddf15ca030ace978f2da87b79b4f504f1d15b5b96c654f6cd5179b72ed5f84d3a16a8f0d5bf6774e7fd98d27bf3c9839',16)
c2 = int('129d5d4ab3f9e8017d4e6761702467bbeb1b884b6c4f8ff397d078a8c41186a3d52977fa2307d5b6a0ad01fedfc3ba7b70f776ba3790a43444fb954e5afd64b1a3abeb6507cf70a5eb44678a886adf81cb4848a35afb4db7cd7818f566c7e6e2911f5ababdbdd2d4ff9825827e58d48d5466e021a64599b3e867840c07e29582961f81643df07f678a61a9f9027ebd34094e272dfbdc4619fa0ac60f0189af785df77e7ec784e086cf692a7bf7113a7fb8446a65efa8b431c6f72c14bcfa49c9b491fb1d87f2570059e0f13166a85bb555b40549f45f04bc5dbd09d8b858a5382be6497d88197ffb86381085756365bd757ec3cdfa8a77ba1728ec2de596c5ab',16)e1 = int('0x1001',16)
e2 = int('0x101',16)
c11 = int('2639c28e3609a4a8c953cca9c326e8e062756305ae8aee6efcd346458aade3ee8c2106ab9dfe5f470804f366af738aa493fd2dc26cb249a922e121287f3eddec0ed8dea89747dc57aed7cd2089d75c23a69bf601f490a64f73f6a583081ae3a7ed52238c13a95d3322065adba9053ee5b12f1de1873dbad9fbf4a50a2f58088df0fddfe2ed8ca1118c81268c8c0fd5572494276f4e48b5eb424f116e6f5e9d66da1b6b3a8f102539b690c1636e82906a46f3c5434d5b04ed7938861f8d453908970eccef07bf13f723d6fdd26a61be8b9462d0ddfbedc91886df194ea022e56c1780aa6c76b9f1c7d5ea743dc75cec3c805324e90ea577fa396a1effdafa3090',16)
c22 = int('42ff1157363d9cd10da64eb4382b6457ebb740dbef40ade9b24a174d0145adaa0115d86aa2fc2a41257f2b62486eaebb655925dac78dd8d13ab405aef5b8b8f9830094c712193500db49fb801e1368c73f88f6d8533c99c8e7259f8b9d1c926c47215ed327114f235ba8c873af7a0052aa2d32c52880db55c5615e5a1793b690c37efdd5e503f717bb8de716303e4d6c4116f62d81be852c5d36ef282a958d8c82cf3b458dcc8191dcc7b490f227d1562b1d57fbcf7bf4b78a5d90cd385fd79c8ca4688e7d62b3204aeaf9692ba4d4e44875eaa63642775846434f9ce51d138ca702d907849823b1e86896e4ea6223f93fae68b026cfe5fa5a665569a9e3948a',16)n2 = 'PVNHb2BfGAnmxLrbKhgsYXRwWIL9eOj6K0s3I0slKHCTXTAUtZh3T0r+RoSlhpO3+77AY8P7WETYz2Jzuv5FV/mMODoFrM5fMyQsNt90VynR6J3Jv+fnPJPsm2hJ1Fqt7EKaVRwCbt6a4BdcRoHJsYN/+eh7k/X+FL5XM7viyvQxyFawQrhSV79FIoX6xfjtGW+uAeVF7DScRcl49dlwODhFD7SeLqzoYDJPIQS+VSb3YtvrDgdV+EhuS1bfWvkkXRijlJEpLrgWYmMdfsYX8u/+Ylf5xcBGn3hv1YhQrBCg77AHuUF2w/gJ/ADHFiMcH3ux3nqOsuwnbGSr7jA6Cw=='
n2 = bytes_to_long(base64.b64decode(n2))
n3 = 'TmNVbWUhCXR1od3gBpM+HGMKK/4ErfIKITxomQ/QmNCZlzmmsNyPXQBiMEeUB8udO7lWjQTYGjD6k21xjThHTNDG4z6C2cNNPz73VIaNTGz0hrh6CmqDowFbyrk+rv53QSkVKPa8EZnFKwGz9B3zXimm1D+01cov7V/ZDfrHrEjsDkgK4ZlrQxPpZAPl+yqGlRK8soBKhY/PF3/GjbquRYeYKbagpUmWOhLnF4/+DP33ve/EpaSAPirZXzf8hyatL4/5tAZ0uNq9W6T4GoMG+N7aS2GeyUA2sLJMHymW4cFK5l5kUvjslRdXOHTmz5eHxqIV6TmSBQRgovUijlNamQ=='
n3 = bytes_to_long(base64.b64decode(n3))gcd = gmpy2.gcdext(e1,e2)
s,t = int(gcd[1]),int(gcd[2])
n1 = (pow(c11,s,n3)*pow(c22,t,n3))%n3
#2499586809914462821807624371088011200618603528498132509598946284572455726453497171635086810524607288333625665025664872216634366700044105279185519761587818169021167370991396691510275499486673922916370294043072503635630922980240462022218565365191228535222150496387990987123639567257124081274667568443678527637259644488779394704508217357758791670308548246801142468699716221789070607334747835552167450340441488756779323653879402176647890584656379628685893686585469918686253137796663587854943386347039389769790329948165162483370187914412810153613198247569427480466488647563900948387020677830797976534568626241686906738179p1 = 68475150402136550069561649755295544963289030785101058202360554598728892273874900512013972536010281921862638482624050145776516868431210229550944533343142576416459199101144902197593841367980791503251475193609136925280837184839979646652186999511796418448787979170775450657311911945185202715164053596280658868979
p3 = 113057116110640629442838729892384636071708596904428483152114609685936140664770589059214780753000125747653792221591510804947737833483206498631262985233023673075253476613965561679900695245558177430781375269136603105651856671527157586176048122119973067362460787539110922411635014408169669810929828500304139655817
p2 = 36503560711222200347745635238792106713920033958622200829092748503591270659903081394620276506325026411074230626397319741508641600002903305233380003999170571805545704321579972221393658587490213987917997698711182322920804807669281318998024155277432216030985270653843416557319053811218180174081048812060180634801phi1 = (p1-1)*(p2-1)
phi2 = (p1-1)*(p3-1)
d1 = int(gmpy2.invert(e,phi1))
d2 = int(gmpy2.invert(e,phi2))
msg1 = long_to_bytes(pow(c1,d1,n1))
msg2 = long_to_bytes(pow(c2,d2,n2))
#print(msg1,msg2)
#print(len(msg1),len(msg2))#21 20 len(flag) = 41def separate(n):p = n % 4t = (p*p) % 4return t == 1flag = ''
cnt1 = 0
cnt2 = 0
msg1 = bytes.decode(msg1)
msg2 = bytes.decode(msg2)
for i in range(41):if separate(i):flag +=  msg2[cnt2]cnt2 += 1else:flag +=  msg1[cnt1]cnt1 += 1print(flag)

3.[NPUCTF2020]认清形势,建立信心

假设c1 = pow(2, e, n)) , c2 = pow(4, e, n) , c3 = pow(8, e, n)
则c2 = pow(c1,2,n) , c3 = pow(c1,3,n)
即c2 = c12 + t1 * n , c3 = c13 + t2 * n
从而num = c12 + c13 -c2 - c3 = k * n

求出的n应该是唯一的,所以要找到限制条件。分析c1,c2,c3的长度以及 c12 的长度可以知道15 <= len(n) < 29,我这里猜的是len(n) = 15。但是通过枚举的话可能行不通(n可能是由num中的中间两个因数构成,而枚举的话是从小到大排除),所以我们可以直接分解出num的所有因数,找两个长度相同的试一下(题目中p,q一般长度相同)。
在这里插入图片描述
这里找到了18195301和28977097,发现两个相乘后的长度正好为15,应该就是p,q了。
至于求e的话,我们可以使用sympy.discrete_log()来求,这个方法在上次的wp中介绍过。

from Crypto.Util.number import *
import gmpy2,sympyc = 169169912654178
c1 = 128509160179202
c2 = 518818742414340
c3 = 358553002064450
#print(pow(c1,2) == c2)#false 说明len(c**2)>len(n)>=len(c1)
#c2 = pow(c1,2,n) c2 = c1**2 + t1*n
#c3 = pow(c1,3,n) c3 = c1**3 + t2*n
#c1**2+c1**3-c2-c3 = (t1+t2)*n = k*n
num = pow(c1,2) + pow(c1,3) - c2 - c3
#print(num)
''' k = 2 while True:if num%k==0:n = num//kif len(str(n))==15:print(k)print(n)breakk += 1 '''
p = 18195301
q = 28977097
n = p*q
phi = (p-1)*(q-1)
e = sympy.discrete_log(n,c1,2)
d = int(gmpy2.invert(e,phi))m = pow(c,d,n)print(long_to_bytes(m))

4.[UTCTF2020]OTP

一次性密码(One Time Password,简称OTP),又称“一次性口令”,是指只能使用一次的密码。一次性密码是根据专门算法、每隔60秒生成一个不可预测的随机数字组合。
OTP Crack
在这里插入图片描述
这貌似给出的东西已经有了,不过这个格式倒是提醒了将a xor a的十六进制数按照两两一组进行chr(),得到
utflag{tw0_tim3_p4ds}utflag{tw0_tim3_p