从Header到Cookie:sqli-labs19~20关的进阶注入思维

admin 2026-01-13 14:59:28 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细解析sqli-labs第19至20关的进阶SQL注入技巧。第19关演示基于Referer头的INSERT型报错注入,利用updatexml构造闭合Payload获取数据。第20关针对Cookie参数,分析后端混合执行的SELECT与UPDATE语句逻辑,分别实施布尔盲注与报错注入。文章强调渗透测试需关注请求全要素,还原后端执行逻辑是漏洞挖掘的核心。 综合评分: 88 文章分类: WEB安全,渗透测试,漏洞分析


cover_image

从 Header 到 Cookie:sqli-labs 19~20 关的进阶注入思维

武文学网安

2026年1月12日 00:31 西藏

大家好,我是武文。

在第 18 关中,我第一次遇到这样一种情况:页面参数全部安全,但 SQL 注入点却藏在 HTTP Header 中。第 18 关让我意识到一个关键问题: SQL 注入不只发生在“参数里”,而是发生在“请求中”。而第 19、20 关,正是在这个基础上的进一步升级

一、第19关:注入不再死板,学会举一反三

因为昨天的教训,我们不再死板的盯着username/password,亦或者User-Agent。既然是SQL注入,理论上,只要用户可控的数据参与了数据库操作,且未被正确过滤,就可能成为注入点。先对页面情况测试,分别尝试错误的和正确的账号密码,观察页面变化。

当输入错误的账号密码时,页面显示

当输入正确的账号密码时,admin:admin

页面显示成功登录,同时,还显示了Your IP ADDRESS is: 172.17.0.1 Your Referer is: http://192.168.68.172:8080/Less-19/

通过过查阅header相关资料发现,referer是一个请求头的信息,包含了当前请求页面的来源页面的地址。资料来源参考:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Headers/Referer

结合昨天学到的header注入,由于页面在登录成功后主动回显了 Your Referer is: …,说明该字段被后端读取并参与了业务处理,而这类“被记录的信息”正是 Header 注入最常见的入口。有理由怀疑注入参数大概率就是referer。让我们先手动测试注入点。

首先利用Burp suite抓包进行注入点测试。(这里是假设前面的url和payload注入方式都已判断失效哈,节约时间)

Referer:'

这里能明显看到单引号引入导致了语法错误:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘172.17.0.1’)’

再头铁尝试一下构造真假语句看效果:

referer:' and 1=1 #referer:' or 1=1 #referer: #

再’ and 1=1#报错,You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ” at line 1

这里可以猜测大概率后端SQL语句非查询语句,而是插入语句:

INSERT INTO referers (referer, ip_address, username)VALUES ('Referer内容', 'IP', 'admin');或者INSERT INTO logs (username, referer)VALUES ('admin', 'Referer内容');

‘ and 1=1在下面的场景中合法:

SELECT * FROM users WHERE username='xxx' and 1=1;

但当在VALUES场景下,注入后,SQL实际变成:

INSERT INTO referers (...)VALUES ('' and 1=1 #', 'IP', 'admin');

本质原因在于: VALUES 中只能是“值表达式”,而不是条件判断语句。

既然我们确认

  • 是INSERT,
  • # 被当作字符串,无法注释和闭合语法。因为在 INSERT 的 VALUES 场景中,当前 payload 仍然位于字符串上下文中,# 并未跳出 SQL 结构,因此不会被解析为注释符,而只是普通字符
  • 通过逻辑判断方法无效。

我们则需要构造一个必然报错的SQL函数,并把数据拼进错误信息,这与第18关一样。SQL注入实战——HTTP Header注入,新的注入思路

需要做到的三件事:

  • 关闭当前字符串
  • 执行一个会报错的表达式
  • 再补一个字符串,保证 VALUES 语法完整

可行的Payload

Referer:' and updatexml(1,concat(0x7e,database(),0x7e),1) and '

注入后SQL实际形态:

INSERT INTO referers (referer, ip_address, username)VALUES (  '' and updatexml(1,concat(0x7e,database(),0x7e),1) and '',  '172.17.0.1',  'admin');

这里有几个关键点:

  • updatexml()必然报错
  • concat() 把 database() 拼进错误信息
  • 两侧的 ' 是为了 修复 VALUES 语法
  • and 在这里是布尔表达式连接,不是 WHERE

👉 所以这在 INSERT 中是合法的表达式结构

下面进行实战测试:

再用sqlmap自动化验证:

1、将burp suite抓取到的请求内容复制零存为req.txt

2、输入命令

python sqlmap.py -r "‪C:\Users\demon\Desktop\security\req.txt" --batch -p Referer --level=5 --risk=3

sqlmap也能跑出error-based的注入方式。

二、第 20 关:从 Header 进入 Cookie

如果说第 19 关考察的是“是否能从请求头中识别新的注入入口”,那么第 20 关则更进一步,引入了业务逻辑与多条 SQL 并存的真实场景。

为什么说第 20 关更危险?

因为这一次,注入点在:Cookie

这意味着:

  • 每次请求都会自动携带
  • 开发极易忽略安全校验
  • 与用户身份、状态强绑定

相比 Header,Cookie 更“隐蔽”,也更贴近真实 Web 应用。

我们先来看正确登陆后的页面状态:

页面反馈了我们登录的cookie状态。

通过burp suite抓包查看信息。这里注意我们看

在输入账号密码登陆时,服务端返回了一个Set-Cookie: uname=admin; expires=Sun, 11-Jan-2026 12:33:32 GMT; Max-Age=3600  这是指定了cookie的有效时间。

而在后面的GET请求中则可以看到我们的header中就包含了Cookie:uname=admin

这里我尝试

Cookie:uname='

发现cookie中的数据是直接拼接到SQL语句中,从而引入了SQL报错。这里其实并不能确定后台数据是查询还是插入。于是我继续用以前的方法尝试:

Cookie:uname=' or 1=1 #  Cookie:uname=' and 1=1 #Cookie:uname=' and 1=2 #

当uname=’ or 1=1#,能够正常显示,推测后端执行了查询语句,而当uname=’ and 1=1#,和uname=’ and 1=2#,虽然能够显示出cookie,但下面都显示异常:bug off you silly dumb hacker。所以这里可以大胆推测后端执行了两条语句,一条是select查询语句,一条是insert或者update更新语句。后端最合理的执行流程应该是如下四步:

1、从cookie中取出uname值

2、用uname查询用户:这一步决定是否有正确用户,因为正确登录和错误登录会有不同页面,所以这是布尔盲注生效的地方。

3、记录/更新Cookie(Insert或update):这一步主要是记录访问,或刷新会话状态,或维持当前用户cookie生命周期。

4、重新set-cookie

我们需要来判断到底哪条语句可以利用。

判断可利用的 SQL 语句位置

从前面的现象可以确定:

  • SELECT 查询语句 决定了页面是否显示正常用户信息,是否返回 BUG OFF YOU SILLY DUMB HACKER → 这是一个典型的布尔盲注利用点
  • INSERT / UPDATE 语句 负责记录或更新 Cookie 状态 → 即使 SELECT 查询失败,这一步依然会执行

也就是说,这一关中:SELECT 用来“判断真假”,INSERT / UPDATE 用来“维持状态”。因此,真正可控、可用于数据判断的,是 SELECT 查询语句

再次尝试能否像前两关一样利用显错注入。构造payload

Cookie:uname=' and updatexml(1,concat(0x7e,database(),0x7e),1) and '

实践发现,依然可以利用XPATH显错注入。

我们再次利用sqlmap来进行验证我们的判断:

在 Cookie 注入场景下,需要显式告诉 sqlmap 从 Cookie 中取参数,否则很容易漏掉注入点。(小坑注意一下:我测试用默认的参数而未指明时明显测不出来)

python sqlmap.py -u "http://localhost:8080/Less-20" --cookie="uname=admin" --batch --level=2 --risk=2

可以看到当前关卡存在多种注入方式。

结语

从第 18 关到第 20 关,SQL 注入的“注入点”不断变化:从参数,到 Header,再到 Cookie。

但真正变化的,并不是 payload,而是思考方式

第 19 关让我学会:不要只盯着输入框,而要看整个请求。

第 20 关则进一步让我意识到: 一次请求中,可能同时存在多条 SQL 语句,而页面表现只反映了其中一部分结果。

也正是从这一阶段开始,我逐渐明白—— SQL 注入的核心,不是技巧,而是还原后端的执行逻辑

这,才是真正接近实战的地方。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:武文学网安 《从 Header 到 Cookie:sqli-labs 19~20 关的进阶注入思维》

迟来的2025年小结 网络安全文章

迟来的2025年小结

文章总结: 本文总结作者2025年的个人成长与工作重心。生活方面坚持读书与旅行;工作方面聚焦AI安全,保障AI业务落地并通过AI4SDL升级体系,重塑风控技术架
评论:0   参与:  0