Reverse

坐大牢。就出了签到题。剩余的等复现罢。

whereisyourkey

签到题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v5 = [118,103,112,107,99,109,104,110,99,105]

for i in range(len(v5)):
if v5[i] == 109:
continue
if v5[i] <= 111:
if v5[i] <= 110:
v5[i] -= 2
else:
v5[i] += 3

for i in range(len(v5)):
print(chr(v5[i]),end = '')
# yesiamflag

ezzzzre

ExeinfoPE打开,发现UPX壳,直接-d没毛病。

IDA打开发现加密算法,输入8位Str加密后与"HELLOCTF"一一比对。

1
2
3
4
5
6
7
a = "HELLOCTF"

flag = ''
for i in range(8):
flag += chr(ord(a[i])*2-69)
print(flag)
# KESSYAcG

套上UNCTF{}后提交。

Crypto

md5-1 & md5-2

md5查询网站:https://www.cmd5.com

需要注意的是md5-2多加了一段异或:

1
2
3
4
5
6
7
8
for i in range(0,len(md5_)):
if i==0:
with open('out.txt','a')as file:
file.write(hex(md5_[i])[2:]+'\n')
else:
with open('out.txt','a')as file:
file.write(hex(md5_[i]^md5_[i-1])[2:]+'\n')

反向解出即可:

1
2
3
4
5
6
7
8
with open("C:\\User\\dell\\Desktop\\md5-2\\md5-2\\out.txt") as f:
data = f.readlines()

for i in range(1,len(data)):
data[i] = hex(int(data[i],16)^int(data[i-1],16))

for i in range(len(data)):
print(data[i])

dddd

附件如下:

1
110/01/0101/0/1101/0000100/0100/11110/111/110010/0/1111/10000/111/110010/1000/110/111/0/110010/00/00000/101/111/1/0000010

一眼摩斯码。以1为-、0为.尝试,未果。遂以1为.0为-,解码得UNCTF{Y4S_TH1S_JUST_M0RSE}

caesar

附件如下:

1
2
3
我把表换成了base64的表

B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY_}

已知flag前5位为UNCTF,对照base64表得位移为19。

破解程序如下(偷懒了,不想写判断条件就把表复制了一份):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
base64_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/']
c = 'B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY_}'
flag = ''
for i in range(len(c)):
if c[i] in base64_list:
for j in range(64):
if c[i] == base64_list[j]:
flag += base64_list[j+19]
break
else:
flag += c[i]
print(flag)
# UNCTF{w0w_Th1s_d1fFerent_c4eSar_}

ezRSA

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import libnum

p=libnum.generate_prime(256)
e=65537
m=flag

m=libnum.s2n(m)
n=p**4
phi_n=p**4-p**3
d=libnum.invmod(e,phi_n)
c=pow(m,e,n)

print ("n=",n)
print ("e=",e)
print ("c=",c)
'''
62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
65537
56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504
'''

直接开根。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import gmpy2
from Crypto.Util.number import *

n = 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
e = 0x10001
c = 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504

p,isroot = gmpy2.iroot(n,4)
phi = p**4-p**3
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
# unctf{pneum0n0ultram01cr0sc0p01cs01l01c0v0lcan0c0n010s01s}

Single Table

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ABCDEFGHIKLMNOPQRSTUVWXYZ
key="ABCD"
table=
[
E,F,G,H,I,
K,L,M,N,O,
P,Q,R,S,T,
U,V,W,X,Y,
Z,A,B,C,D
]
明文=THE_CODE
整理为:TH EC OD EX
密文为:IS ZH TI UH
整理为:ISZ_HTIU

密文:ISZ_HTIUH
整理为:IS ZH TI UH
明文为:TH EC DO EX
整理为:THE_CODE

1
2
key="PLAY"
OTUBM{BCQ_SPH_WOQA_UAYFMKLWS}

移位丁真,鉴定为Playfair。规律如下:

  1. 选取一串英文字母,除去重复出现的字母,将剩下的字母逐个逐个加入 5 × 5 的矩阵内,剩下的空间由未加入的英文字母依 a-z 的顺序加入。注意,将 q 去除,或将 i 和 j 视作同一字。
  2. 将要加密的明文分成两个一组。若组内的字母相同,将 X(或 Q)加到该组的第一个字母后,重新分组。若剩下一个字,也加入 X 。
  3. 在每组中,找出两个字母在矩阵中的地方。
  • 若两个字母不同行也不同列,在矩阵中找出另外两个字母(第一个字母对应行优先),使这四个字母成为一个长方形的四个角。
  • 若两个字母同行,取这两个字母右方的字母(若字母在最右方则取最左方的字母)。
  • 若两个字母同列,取这两个字母下方的字母(若字母在最下方则取最上方的字母)。

易得flag为UNCTF{GODY_OUK_NOWP_LAYFAIR}

Multi Table

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from string import ascii_uppercase
from random import randint,shuffle
from binascii import b2a_hex,a2b_hex

flag="UNCTF{}"
base_table=list(ascii_uppercase)
shuffle(base_table)
print(base_table)

table={}
for i in range(26):
table[i]=ascii_uppercase[i:]+ascii_uppercase[:i]

key=[]
for i in range(4):
key.append(randint(0,25))
# print(key)
c=''
x=0
for i in range(len(flag)):
if flag[i] in ascii_uppercase:
c+=table[key[x%4]][base_table.index(flag[i])]
x+=1
else:
c+=flag[i]
print(c)

# ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
# SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}

大致过程如下:

  1. 取大写字母列表用shuffle()洗牌后作为base_table,之后循环移位存入table。所以table里有26张打乱的字母表。(维吉尼亚密码的特征)
  2. 随机取4个key,值为[0,25]。之后将key作为读table的一个下标,也就是key决定读table的第几张表。
  3. 逐位取flag,取其在base_table里的位置后映射到table[key%4]。

所以我们可以利用flag已知的前五位UNCTF判断4位key,最后一位作为校验。

破解程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from string import ascii_uppercase
base_table=['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
table={}
for i in range(26):
table[i]=ascii_uppercase[i:]+ascii_uppercase[:i]
# print(table)
flag1 = 'UNCTF'
flag = ''
c = 'SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}'
key = [0,0,0,0,0]
for i in range(5):
key[i]=base_table.index(flag1[i])
for j in range(26):
if table[j][key[i]]==c[i]:
key[i] = j
break
x = 0
for i in range(len(c)):
if c[i] in ascii_uppercase:
for j in range(26):
if table[key[x%4]][j]==c[i]:
flag += base_table[j]
x += 1
break
else:
flag += c[i]

print(flag)
# UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}

babyRSA

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from secret import flag
import libnum
flag="UNCTF{*************************}"
m=libnum.s2n(flag)
p=libnum.generate_prime(1024)
q=libnum.generate_prime(1024)
n=p*q
e=6
c=pow(m,e,n)
M=((m>>60)<<60)
print("n=",n)
print("c=",c)
print("((m>>60)<<60)=",M)

'''
25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
'''

参考Coppersmith攻击(已知m的高位攻击)

eazy_RSA

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from gmpy2 import *
from secret import flag
import random
assert flag.startwith(b"flag{")
e=0x10001
c=6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
m=bytes_to_long(flag)
p=getprime(512)
q=getprime(512)
n=p*q
c=pow(m,e,n)
print("n={}".format(n))
print("c={}".format(c))
tmp=random.randint(100,300)
print("p>>tmp={}".format(p>>tmp))

#p>>200=8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857

参考Coppersmith攻击(已知p的高位攻击)

ezxor

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from key import m,flag

def xor(a, b):
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])

def OPT(key,crypto):
ciphertext=xor(key,crypto)
return ciphertext

ls=[]

for i in range(11):
ls.append(m[i*42:(i+1)*42])

for x in ls:
k=OPT(flag,x).encode('hex')
print(k)

'''
1c2063202e1e795619300e164530104516182d28020005165e01494e0d
2160631d325b3b421c310601453c190814162d37404510041b55490d5d
3060631d325b3e59033a1252102c560207103b22020613450549444f5d
3420277421122f55067f1207152f19170659282b090b56121701405318
212626742b1434551b2b4105007f110c041c7f361c451e0a02440d010a
75222a22230877102137045212300409165928264c091f131701484f5d
21272d33661237441a7f005215331706175930254c0817091b4244011c
303c2674311e795e103a05520d300600521831274c031f0b160148555d
3c3d63232909355455300752033a17175e59372c1c0056111d01474813
752b22272f1e2b10063e0816452b1e041c593b2c02005a450649440110
396e2f3d201e795f137f07130c2b1e450510332f4c08170e17014d481b
'''

多次一密。把flag作为密钥与明文进行异或加密。具体解题思路可参考这篇文章

这里说一下大致解题思路。因为c1=m1^key c2=m2^key,所以c1^c2=m1^key^m2^key=m1^m2。又因为小写字母^32(空格的ASCII码)=大写字母 大写字母^32=小写字母,我们可以把其中一段密文与其他密文两两异或(等价于明文两两异或)后计算字母的个数,如果该位置字母出现概率很高的话,基本可以确定该位置的明文是个空格。之后根据key=c1^m1求密钥即可。

破解程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
k = [...] # 此处省略数据

spacelim = 5 # 空格出现多少算“多”

spacecnt = [0 for i in range(29)]

for n in range(11):
for i in range(11):
if n==i:
continue
for j in range(29):
mwtmp = int(k[i][j*2:(j+1)*2],16)^int(k[n][j*2:(j+1)*2],16)
if 65<=mwtmp<=90 or 97<=mwtmp<=122:
spacecnt[j] += 1
flagtmp = ''
for j in range(29):
if spacecnt[j] >=spacelim:
tmp = int(k[n][j*2:(j+1)*2],16)^32
if 32<=tmp<=126:
flagtmp += chr(tmp)
else:
flagtmp += ' '
else:
flagtmp += ' '
print(flagtmp)
spacecnt = [0 for i in range(29)]
'''
output:
C Y 6e e 8 " ~!
C { !e 6 e u -}
C { r v 0 " e i }
T _ ' y ) v !
T a% _ <_ e d-!
U W0 r y l ! }
F _ r y l b !
T Y r r8 l ! }
C u r ~y v !
U 0 6e y " ze i !
N Y _ 3 e 0 l !
'''

可以看到部分位置的字符还是很明显的,但是有一些位置还是很迷惑(比如那个~)

我们可以通过猜测这些位置的字符来构造密钥,之后与密文异或后对得出的明文进行语义分析即可。

Flag为UNCTF{Y0u_are_very_Clever!!!}

Today_is_Thursday_V_me_50

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
from flag import flag

name = "unctf"
key1 = TOPIC # 'Today_is_Thursday_V_me_50' ——Cabelis注
key1_num = bytes_to_long(key1)


def encrypt_1(message,name):
res = message
guess=[i for i in itertools.permutations(name, 5)]
for i in range(4):
what = guess.pop(50)
name = ''.join(j for j in what)
mask = strxor(5*name.encode(),key1)
res = strxor(mask,message) # res = flag ^ 5*name ^ key1
return res


def encrypt_2(message,num):
random.seed(num)
res_2 = b''
for i in message:
temp_num = random.randint(1,128)
res_2 += long_to_bytes(temp_num ^ i)
return res_2


if __name__ == '__main__':
x = encrypt_2(encrypt_1(flag,name),key1_num)
print(x)

# b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P'

这个TOPIC真让人迷惑啊。看一眼题目条件还有V我50没用,索性就是这个。

除去这个之外就是普通的字符串异或。itertools.permutations(list,num)是在list中取遍大小为num的排列的意思。

破解程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor

name = "unctf"
key1 = b'Today_is_Thursday_V_me_50'
key1_num = bytes_to_long(key1)
c = b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P'

res = b''
random.seed(key1_num)
for i in c:
temp_num = random.randint(1,128)
res += long_to_bytes(temp_num ^ i)

guess=[i for i in itertools.permutations(name, 5)]
for i in range(4):
what = guess.pop(50)
name = ''.join(j for j in what)
mask = strxor(5*name.encode(),key1)
flag = strxor(mask,res)

print(flag)
# unctf{1_l0ve_Thurs4Ay!!!}

谨防新型网络诈骗(bushi

Fermat

附件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import *
from gmpy2 import *

flag=b'UNCTF{}'
e=0x10001
p=getPrime(1024)
q=getPrime(1024)
n=p*q
m=bytes_to_long(flag)
c=pow(m,e,n)
x=getPrime(1024)
assert gift+x==x*p #gift==x*(p-1)
print(n)
print(c)
print(gift)

# 19793392713544070457027688479915778034777978273001720422783377164900114996244094242708846944654400975309197274029725271852278868848866055341793968628630614866044892220651519906766987523723167772766264471738575578352385622923984300236873960423976260016266837752686791744352546924090533029391012155478169775768669029210298020072732213084681874537570149819864200486326715202569620771301183541168920293383480995205295027880564610382830236168192045808503329671954996275913950214212865497595508488636836591923116671959919150665452149128370999053882832187730559499602328396445739728918488554797208524455601679374538090229259
# 388040015421654529602726530745444492795380886347450760542380535829893454552342509717706633524047462519852647123869277281803838546899812555054346458364202308821287717358321436303133564356740604738982100359999571338136343563820284214462840345638397346674622692956703291932399421179143390021606803873010804742453728454041597734468711112843307879361621434484986414368504648335684946420377995426633388307499467425060702337163601268480035415645840678848175121483351171989659915143104037610965403453400778398233728478485618134227607237718738847749796204570919757202087150892548180370435537346442018275672130416574430694059
# 28493930909416220193248976348190268445371212704486248387964331415565449421099615661533797087163499951763570988748101165456730856835623237735728305577465527656655424601018192421625513978923509191087994899267887557104946667250073139087563975700714392158474439232535598303396614625803120915200062198119177012906806978497977522010955029535460948754300579519507100555238234886672451138350711195210839503633694262246536916073018376588368865238702811391960064511721322374269804663854748971378143510485102611920761475212154163275729116496865922237474172415758170527875090555223562882324599031402831107977696519982548567367160

费马小定理的应用。准确来说是Pollard’s p-1算法:

这里的B其实就是上面代码中的gift变量。

破解程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import math

def pollard(N):
print('n可以分解为:')
while 1:
B= 28493930909416220193248976348190268445371212704486248387964331415565449421099615661533797087163499951763570988748101165456730856835623237735728305577465527656655424601018192421625513978923509191087994899267887557104946667250073139087563975700714392158474439232535598303396614625803120915200062198119177012906806978497977522010955029535460948754300579519507100555238234886672451138350711195210839503633694262246536916073018376588368865238702811391960064511721322374269804663854748971378143510485102611920761475212154163275729116496865922237474172415758170527875090555223562882324599031402831107977696519982548567367160
a=2
a=pow(a,B,int(N))
d=math.gcd(a-1,int(N))
if 1<d<N:
print(d)
N=N/d
else:
print(int(N))
break

n = 19793392713544070457027688479915778034777978273001720422783377164900114996244094242708846944654400975309197274029725271852278868848866055341793968628630614866044892220651519906766987523723167772766264471738575578352385622923984300236873960423976260016266837752686791744352546924090533029391012155478169775768669029210298020072732213084681874537570149819864200486326715202569620771301183541168920293383480995205295027880564610382830236168192045808503329671954996275913950214212865497595508488636836591923116671959919150665452149128370999053882832187730559499602328396445739728918488554797208524455601679374538090229259
pollard(n)

分解n后常规做法。

写在最后

某密码的脚本小子。
这次一定把剩下做过的题目复现一下,大牢不能白坐了。