【总结笔记】web
零碎知识点
任意文件读取漏洞
- 25星芒杯,
?file=/flag&filter=base64,bash编码输出防止乱码
SQL注入
sql查询
select * from users where id = 1;或者where id in ('3')- 子查询:括号内先执行,
select * from users where id = (select id from users where name = admin) - union
- 保证前后列数一致
- 列数判断
- group by(有点小问题但可以帮助waf绕过)
- 二分法判断列数
- group by n开始报错,说明只有n-1列
- order by
- desc降序
- group by(有点小问题但可以帮助waf绕过)
limit a,b;从第a+1行开始显示b行(从0行开始算)- and or
- 判断闭合关系
- 万能钥匙or
- 常用函数
- group_concat:多行变一行
select group_concat(id,name)...
- select database():查看数据库名称
- elect version():版本
- group_concat:多行变一行
SQL注入基础
- SQL注入,就是通过把SQL命令插入到WEB表单提交或输入域名或页面请求的查询字符串,最终到达欺骗服务器执行恶意的SQL 命令,从而进一步得到相应的数据信息。
- 通过构造一条精巧的语句,来查询到想要得到的信息。
- 注入分类
- 按照输入的参数
- 字符型
- 数字型
- 使用and1=1和and1=2来判断
- 后者有回显:字符型(''包括了后面的and1=2);无回显:数字型,and1=2错误
- 使用计算判断
- 数字型有计算:1和2-1的结果是否相同
- 数字型一般提交内容为数字,但数字不一定为数字型
- 按照注入方法
- Union注入,报错注入,布尔注入,时间注入
- 注入点
- 闭合方式:’ " ') ") other
- 尝试输入’ " 然后看报错
- 手工提交闭合符号,结束前一段查询语句,后面即可加入其他语句,查询需要的参数
- 不需要的语句可以用注释符号
--+或#或%23注释掉- 注释掉:利用注释符号暂时将程序段脱离运行
- 把某段程序“注释掉”,就是让它暂时不运行(而非删除掉)。
- union联合注入
- 先判断列数!!!
- 查询回显位
- 总结流程:
- 查找注入点
- 判断是字符型还是数字型注入
- 如果字符型,找到他的闭合方式
- 判断查询列数
- 查询回显位置,不需要的-1实现不显示
union select 1,2,3 --+
union注入
- 拿到表名,列名
- 默认自带:
- Information_schema:包含所有mysql数据库的简要信息
- tables:表名集合表
- columns:列名集合表
- 默认自带:
- 使用:
union select table_name from information_schema.tables where table_schema=database(); --+union select column_name from information_schema.columns where table_schema=database() and table_name='自己填上一步得到的';--+- group_concat()放在select后,只包围回显位!!!还可以插入~区分数据
- 例如
' or 1=1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database(); # group_concat(a,'~',b)
- 例如
- 查列名对应内容:(假设查列名为a,b的内容)
union select 1,group_concat(a,'~',b),3 from 表名 --+v
- 暂时学到这里
https://www.bilibili.com/video/BV1c34y1h7So?buvid=XU97BB69D2A4657727B10BFBF06B3FEB6C6A2&from_spmid=search.search-result.0.0&is_story_h5=false&mid=LOw8O0fR%2FjzSBXlVqIpccw%3D%3D&plat_id=116&share_from=ugc&share_medium=android&share_plat=android&share_session_id=e9cd71d3-484d-4ca1-9dba-5749bf8de4bc&share_source=WEIXIN&share_tag=s_i&spmid=united.player-video-detail.0.0×tamp=1763951829&unique_k=iM5ZV9D&up_id=271803648&vd_source=ddfd8fb754dccf9e433a255c412b8d6c&spm_id_from=333.788.videopod.episodes&p=11
空格过滤绕过方法介绍
- 绕过空格
- 可以代替空格的字符:
+ |
- URL编码对应:
| name | URL |
|---|---|
| spaces | %20 |
| TAB 09 horizontal TAB | %09 |
| LF OA newline | %0A |
| FF OC new page | %0C |
| CR 0D carriage return | %0D |
| VT OB vertical TAB | %OB |
| -OA-(MySQL only) | %A0 |
- 使用报错注入
- 多用括号以达到不适用空格的效果
- and和or复写
?id=1000'||extractvalue(1,concat('$',(database()))||'1'='1
- limit替换函数
- mid()与substr()用法相同
mid(string,start,length)=mid(string from start for length)?id=10o0'||extractvalue(1,concat('$',(select(mid(group_concat(username,):',passwoorrd),1,30))from(users))))||'1'='1- 显示前30个字符
- 详细的自己看
SSTI
说明:
- https://portswigger.net/web-security/server-side-template-injection
- 在许多有关ssti的文章中看到同一张图片,遂通过ai知晓图片来源,以下笔记基于PortSwigger Academy的互动教程进行,以下提及内容若没有标注来源一致视为来源于该教程
- 翻译直接使用edge自带,若有错误请及时联系我修改(如果你原因~~
什么是服务器端模板注入
1. 什么是服务器端模板注入?
- 服务器端模板注入是指攻击者能够利用本地模板语法向模板注入恶意负载,然后在服务器端执行。
- 模板引擎设计为通过将固定模板与波动性数据结合来生成网页。当用户输入直接被连接到模板中,而不是以数据形式传递时,可能发生服务器端模板注入攻击。这使得攻击者能够注入任意模板指令以控模板引擎,通常能够完全控制服务器。顾名思义,服务器端模板注入负载是在服务器端交付和评估的,这使其可能比典型的客户端模板注入更危险。
2. 服务器端模板注入的影响是什么?
- 攻击者可能实现远程代码执行,完全控制后端服务器,并利用其对内部基础设施进行其他攻击。
- 即使在无法实现完整远程代码执行的情况下,攻击者通常仍可利用服务器端模板注入作为多种攻击的基础,从而获得对服务器上敏感数据和任意文件的读取权限。
3. 服务器端模板注入漏洞是如何产生的?
- 服务器端模板注入漏洞出现在用户输入被串接到模板中,而非以数据形式传递时。
- 静态模板仅提供动态内容渲染的占位符,通常不易受到服务器端模板注入的影响。经典例子是一封邮件,会以用户的名字向他们致意,比如以下摘自Twig模板的片段:
$output = $twig->render("Dear {first_name},", array("first_name" => $user.first_name) ); |
- 上ai分析一下:
这是一个非常经典且核心的安全概念:数据与代码分离(Separation of Data and Code)。
这句话之所以不会受到服务器端模板注入(SSTI)的影响,核心原因在于:用户的输入被当成了“被填充的变量”,而不是“构建模板的源代码”。
- 在 Twig(以及大多数现代模板引擎)中,
render函数的工作流程分为两个明确的阶段:
- 编译模板:读取第一个参数(模板字符串
"Dear {first_name},")
- 引擎解析这个字符串的语法结构
- 识别出
"Dear "是静态文本,{first_name}是一个占位符变量- 关键点:在这个阶段,引擎只看第一个参数。因为它是由开发者写死的(Hardcoded),里面没有包含任何不可控的用户输入,所以生成的“模板程序”是绝对安全的
- 填充数据:读取第二个参数即数组
array(...))
- 引擎执行刚才编译好的逻辑:先输出 "Dear ",然后去数组里找 key 为
first_name的值。
- 找到值(例如用户输入了
{{ 7*7 }}),引擎将其视为纯文本数据。- 引擎直接把这个字符串打印出来,而不会回头去重新编译或解析它。
- 对比:什么是危险的写法?
- SSTI 漏洞产生的根本原因,是开发者打破了数据与代码的边界,把用户输入拼接到了第一个参数(模板字符串)中。
- 危险写法示例:
// 错误!直接拼接字符串
$template = "Dear " . $user.first_name . ",";
$output = $twig->render($template);
- 此时的分析逻辑:
- 用户输入名字为
{{ 7*7 }}。- PHP 先进行字符串拼接,变量
$template变成了"Dear {{ 7*7 }},"。- 灾难发生在这里:这个拼接后的字符串被传给了
$twig->render()的第一个参数。- 模板引擎拿到这个字符串,以为这也是开发者写的代码。
- 引擎开始解析语法:它发现了
{{ ... }}标记,认为这是需要执行的指令。- 引擎计算
7*7。- 最终输出结果:
Dear 49,。
- 为了方便理解,可以将其想象成“计算器”:
- 安全写法(你的代码):
你给计算器输入公式A + B(模板),然后告诉它 A=1, B=2(数据)。计算器算出 3。如果你告诉它 A=“5+5”(作为字符串),计算器会报错或者只显示文本,因为它只接受 A 是个数字,不会把 A 里的内容当做新公式。- 危险写法(SSTI):
你让用户拿笔在计算器的电路板上写字。用户写了1+5+5,计算器启动时直接运行了这行代码,算出了 11。
- 结论:只要遵循 “用户输入永远只放在第二个参数(Context Data)中,绝不拼接到第一个参数(Template String)中” 这一原则,SSTI 就无法发生。
-
个人总结:也就是说这段代码把用户输入先存到数组里再被模板调用,这个时候便明确了用户输入的类型是字符串其实并不是ssti没发生的根本原因,原因其实是render函数已经通过第一个参数明确我接下来只要取用数组对应内容填充输出就行所以不会去识别取用部分是否包含命令执行的特征
-
继续教程:
-
这不会受到服务器端模板注入的漏洞,因为用户的名字只是作为数据传递到模板中。
-
然而,由于模板只是字符串,网页开发者有时会在渲染前直接将用户输入串接到模板中。我们举一个类似上述的例子,但这次用户可以在邮件发送前自定义邮件的部分内容。例如,他们可能能够选择所用的名字:
$output = $twig->render("Dear " . $_GET['name']); |
- 在这个例子中,模板中不是传递静态值,而是使用参数 动态生成模板的一部分。由于模板语法在服务器端被评估,这有可能允许攻击者在参数中放置服务器端模板注入有效payload,具体如下:
http://vulnerable-website.com/?name={{bad-stuff-here}} |
- 这类漏洞有时是由于不熟悉安全影响的人设计不当的模板设计意外造成的。如上例所示,你可能会看到不同的组件,其中一些包含用户输入,被串接并嵌入到模板中。在某种程度上,这类似于写得不好的准备语句中出现的SQL注入漏洞。
- 然而,有时这种行为实际上是有意为之。例如,有些网站故意允许某些特权用户,如内容编辑者,按意图编辑或提交自定义模板。如果攻击者能够攻破拥有此类权限的账户,这显然构成了巨大的安全风险。
4. 构建服务器端模板注入攻击
- 识别服务器端模板注入漏洞并策划成功攻击通常涉及以下高层次流程。
- detect-identify-exploit-read-explore-attack
detect
(这一部分原文的edge翻译有点难以理解(我认为,所以只存档原文以及我删改后的ai解释)
Detect |
- 为什么SSTI容易被忽视但又非常危险?
- 被忽视的原因: 这种漏洞本身并不复杂,它之所以经常被漏掉,是因为安全审计人员通常只关注传统的 XSS 或 SQL 注入,如果没有专门去测试模板注入,就很难发现它。
- 利用难度低: 一旦你发现了这个漏洞,利用它来攻击通常是惊人地简单。
- 无沙箱环境(Unsandboxed): 许多模板引擎没有配置“沙箱”(Sandbox)保护。这意味着一旦注入成功,攻击者可以直接执行任意代码(RCE),完全控制服务器。
- 第一步探测手段:Fuzzing(模糊测试)
- 探测方法: 就像找其他漏洞一样,第一步是先确定“这里有没有问题”。最简单的办法是使用 Fuzzing(模糊测试)。
- 具体操作: 向输入框或参数中发送一串模板引擎常用的特殊字符序列。
- 字符示例:
${{<%[%'"}}%\ - 原因: 这些字符(
$、{、%、<%等)是各大主流模板引擎(如 Jinja2, FreeMarker, Smarty, PHP等)的语法标记。 - 如何判断有漏洞? 观察服务器的反应。如果服务器抛出了异常(Exception)或报错,这说明服务器尝试解析了你输入的这些字符,而不是仅仅把它们当做普通文本显示出来。这就是存在 SSTI 漏洞的一个强力信号。
- 上下文(Context)的重要性
-
Fuzzing 不是万能的:
-
情况 A: 就算刚才那串乱码(Fuzzing)没报错,也不代表绝对安全。你必须尝试针对特定上下文的探测方法,漏洞可能藏得更深。
-
情况 B: 就算 Fuzzing 报错了(发现了漏洞),你也不能马上利用。你必须搞清楚当前的注入点是在模板的什么位置(上下文),才能构造出有效的攻击代码(Payload)。
-
两种上下文: SSTI 通常发生在两种不同的代码场景中
- 明文上下文
大多数模板语言允许你自由输入内容,要么直接使用HTML标签,要么使用模板的原生语法,后端会先渲染成HTML格式,然后再发送HTTP响应。例如,在Freemarker中,这条线会渲染成类似的。 render('Hello ’ + username)Hello Carlos
- 明文上下文
这有时会被利用用于XSS,实际上常被误认为是简单的XSS漏洞。然而,通过将数学运算设为参数值,我们可以测试这是否也是服务器端模板注入攻击的潜在入口点。
先学到这里咱得补充学习XSS先
例如,考虑一个包含以下易受攻击代码的模板:
render('Hello ’ + username)
审计时,我们可能会通过请求以下URL来测试服务器端模板注入:
http://vulnerable-website.com/?username=${7*7}
如果结果输出包含 ,这表明数学运算是在服务器端被评估的。这是一个很好的服务器端模板注入漏洞的概念验证。Hello 49
注意,成功评估数学运算所需的具体语法会因所用模板引擎而异。我们将在“识别”步骤中详细讨论。
代码上下文
在其他情况下,漏洞通过用户输入被置入模板表达式中暴露,正如我们之前的电子邮件示例所示。这可能表现为参数中放置一个用户可控制的变量名,例如:
greeting = getQueryParameter(‘greeting’)
engine.render(“Hello +greeting+”, data)
在网站上,最终的URL大致如下:
http://vulnerable-website.com/?greeting=data.username
例如,这会在输出中渲染为 。Hello Carlos
这个上下文在评估时很容易被忽略,因为它没有明显的XSS,几乎与简单的哈希图查找无异。在此语境下测试服务器端模板注入的一种方法是,首先通过向值注入任意 HTML 来确定该参数不包含直接的 XSS 漏洞:
http://vulnerable-website.com/?greeting=data.username
在没有XSS的情况下,通常会导致输出中出现空白条目(只是没有用户名)、编码标签,或者出现错误信息。下一步是尝试用常见的模板语法跳出语句,并在后面注入任意 HTML:Hello
http://vulnerable-website.com/?greeting=data.username}}
如果这再次导致错误或空白输出,说明你要么用错了模板语言的语法,要么如果没有模板式语法有效,服务器端模板注入就无法实现。或者,如果输出和任意HTML都被正确渲染,这表明存在服务器端模板注入漏洞:
Hello Carlos
演讲《服务器端模板注入:现代Web应用的RCE》
- 计划在教程学习后对图片来源的演讲进行阅读
- 学习来源:https://portswigger.net/research/server-side-template-injection
- 很明显不直接听演讲是因为英语水平太烂,但存档演讲视频链接
- 演讲的英文文稿pdf预览/下载入口
6:06 PPT
SSTI-python模板引擎Jinja2注入
参考:



