HTTP头注入实战:sqli-labs第18关手工注入与防御详解

发布时间:2026/10/7 6:50:31

HTTP头注入实战:sqli-labs第18关手工注入与防御详解 1. 靶场环境与第十八关概述sqli-labs是一个经典的SQL注入实战靶场对于想深入理解Web安全攻防特别是手工注入技巧的从业者来说是绕不开的必修课。它模拟了各种真实场景下的注入点从最简单的报错注入到复杂的盲注、堆叠注入难度层层递进。今天要拆解的第十八关是一个典型的“HTTP头注入”场景它打破了我们通常只在URL参数或表单字段中寻找注入点的思维定式将战场转移到了HTTP请求的头部信息里。很多刚接触安全测试的朋友在常规位置测试无果后很容易就放弃了殊不知漏洞可能就藏在User-Agent、Referer甚至X-Forwarded-For这些看似“无害”的请求头里。第十八关正是训练我们这种“视野”的绝佳关卡。这一关的界面通常很简单可能只有一个登录框但常规的账号密码注入尝试都会失败。它的核心在于服务器在验证登录后会将部分HTTP头信息比如User-Agent记录到数据库中而这个记录过程存在SQL注入漏洞。因此攻击链是先通过一个有效的登录可能是一个预设的弱口令获得一个有效的会话或触发记录点然后在后续请求的HTTP头中携带恶意载荷。理解这个流程是通关的关键。它模拟了那些记录用户访问日志、分析用户行为但未对输入进行严格过滤的应用场景在现实中具有相当的普遍性。2. 核心漏洞原理与请求流程拆解要攻克第十八关不能闷头乱试必须先把它的后台逻辑猜个八九不离十。根据关卡常见的实现模式我们可以推断出其核心代码逻辑大致如下登录验证前端提交用户名和密码。后端代码会查询数据库验证凭据是否正确。这里通常不是注入点因为开发者会对这些直接来自用户的输入进行基础过滤或使用预编译语句。登录成功后的操作一旦登录成功应用会执行一些“记录”操作。一个非常常见的操作就是将本次登录成功的用户信息连同他此次请求的User-Agent或Referer字符串一起插入到数据库的某个日志表中。代码可能看起来像这样以PHP为例$username $_POST[username]; $uagent $_SERVER[HTTP_USER_AGENT]; // 直接获取HTTP头 $sql INSERT INTO ua_log (username, uagent, ip) VALUES ($username, $uagent, $remote_addr); $result mysqli_query($conn, $sql);漏洞产生点问题就出在第二点。$_SERVER[‘HTTP_USER_AGENT’]这个变量直接来源于客户端浏览器发送的请求头是完全可由用户控制的。开发者往往认为HTTP头是浏览器自动生成的、可信的从而忽略了对其进行与表单数据同等级别的过滤和转义。当这个未经验证的$uagent变量被直接拼接进SQL语句时注入漏洞便产生了。注入位置因此本关的注入点不在登录的username或password字段而在于登录成功之后任何一个会触发该记录逻辑的请求的HTTP头部。通常我们利用User-Agent或Referer头来实施注入。整个攻击流程可以概括为寻找有效登录凭证 - 在登录请求或后续请求的HTTP头中植入SQL注入载荷 - 触发后台的记录逻辑执行恶意SQL。很多人在第一步就卡住了因为总想着用admin’ or ‘1’’1这种payload去爆破登录其实这一关的登录可能只需要一个简单的已知账号密码对比如admin/admin目的是为了让我们“合法”地进入记录流程。注意在实际测试中务必使用Burp Suite、OWASP ZAP这类拦截代理工具。你需要拦截登录成功后的那个请求或者是登录请求本身如果记录发生在登录验证之后然后修改其HTTP头部字段。3. 手工注入实战从探测到数据获取理论清晰后我们进入实战环节。假设我们已经通过某种方式如查看源码提示、常见弱口令获得了登录凭证admin/admin。3.1 环境准备与请求拦截首先确保你的sqli-labs环境如Docker或PHPStudy搭建的运行正常。打开浏览器访问第十八关页面同时打开Burp Suite并配置好代理。在浏览器中输入用户名admin和密码admin点击登录。先不要在意登录后页面显示什么。迅速切换到Burp Suite的Proxy-Intercept标签页确保拦截是开启的Intercept is on。然后在浏览器中刷新登录后的页面或者进行任何可能触发记录的操作有时登录动作本身就会触发。目的是拦截到那个携带了User-Agent的请求。此时Burp Suite会拦截到一个HTTP请求。重点关注请求头部你会看到类似这样的字段GET /sqli-labs/Less-18/ HTTP/1.1 Host: your-target-ip User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ... Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Connection: close ...3.2 漏洞探测与注入点确认现在我们要验证User-Agent头是否真的存在注入。将拦截到的请求发送到Burp Suite的Repeater模块方便我们反复修改和测试。在Repeater中修改User-Agent头的值。最初的探测通常使用单引号‘来触发SQL语法错误。原始请求头User-Agent: Mozilla/5.0 (...)修改为User-Agent: Mozilla/5.0 (...)点击Send发送请求。观察返回的HTTP响应。如果页面返回了数据库的报错信息如“You have an error in your SQL syntax...”那么恭喜你注入点确认了错误信息明确告诉我们单引号破坏了SQL语句的完整性证明User-Agent的值被直接拼接到SQL语句中且未经过滤。如果页面只是空白或显示正常可以尝试在User-Agent末尾添加‘ and ‘1’’1和‘ and ‘1’’2观察页面返回内容是否有差异这常用于盲注判断。但在第十八关通常设计为报错注入所以看到数据库错误是最直接的证据。3.3 利用报错注入提取信息确认注入点后我们利用数据库报错信息来提取数据。这里以MySQL为例常用的报错函数是updatexml()和extractvalue()。原理updatexml()函数用于更新XML文档但如果其第二个参数XPath路径不符合格式就会产生错误并将我们构造的查询结果包含在错误信息中输出。构造Payload 我们需要将想要查询的语句嵌套在updatexml()函数里。基本格式如下 and updatexml(1, concat(0x7e, (你想要执行的SQL查询语句), 0x7e), 1) and 解释一下开头的‘用于闭合原SQL语句中的前一个单引号。and连接我们的恶意条件。updatexml(1, ..., 1)第一个和第三个参数任意重点是第二个参数。concat(0x7e, ..., 0x7e)0x7e是波浪号~的十六进制。用~包裹查询结果是为了在报错信息中更清晰地看到我们的数据边界。末尾的‘用于闭合原SQL语句中User-Agent值后面的那个单引号。实操步骤获取当前数据库名 将User-Agent修改为User-Agent: Mozilla/5.0 (...) and updatexml(1, concat(0x7e, (database()), 0x7e), 1) and 发送请求。在返回页面的错误信息中你会看到类似这样的内容... ‘~security~’ ...这说明当前数据库名是security。获取数据库中的表名 知道数据库名后接下来查询表名。MySQL的系统表information_schema.tables存储了所有表的信息。User-Agent: Mozilla/5.0 (...) and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schemadatabase() limit 0,1), 0x7e), 1) and 这里limit 0,1表示从第0行开始取1行结果即第一个表。发送请求错误信息会显示第一个表名比如emails。 然后修改limit 1,1获取第二个表名limit 2,1获取第三个以此类推。直到找到可能存放用户凭证或敏感信息的表比如users。获取表的列名 假设我们找到了users表接下来获取它的列名。查询information_schema.columns。User-Agent: Mozilla/5.0 (...) and updatexml(1, concat(0x7e, (select column_name from information_schema.columns where table_schemadatabase() and table_nameusers limit 0,1), 0x7e), 1) and 同样使用limit子句遍历你可能会依次得到id,username,password等列名。最终提取数据 现在我们可以从users表中提取username和password了。User-Agent: Mozilla/5.0 (...) and updatexml(1, concat(0x7e, (select concat(username, :, password) from users limit 0,1), 0x7e), 1) and 这个payload会查询username和password并用冒号连接起来。发送请求错误信息会显示第一行数据例如~Dumb:Dumb~。 修改limit 1,1获取第二行直到遍历完所有数据。实操心得updatexml()函数一次只能返回一行中的一个字段或我们concat后的一个字符串。并且它返回的字符串长度有限制约32KB但实际在报错信息中显示的部分更短通常只能显示几十个字符。如果你要查询的数据很长可能会被截断。这时可以使用substring()函数分段读取例如substring((select group_concat(username) from users), 1, 30)。4. 工具辅助与自动化注入思路虽然手工注入能让我们透彻理解原理但在效率至上的渗透测试中合理使用工具是必要的。对于HTTP头注入Sqlmap依然是利器但需要一些特殊配置。使用Sqlmap进行自动化测试保存请求文件在Burp Suite的Proxy-HTTP history中找到那个成功的登录请求或者触发记录的那个GET请求右键点击选择Save item将其保存为一个文本文件比如less18.req。使用Sqlmap加载请求文件Sqlmap可以通过-r参数直接读取包含完整HTTP请求的文件并自动解析其中的注入点。sqlmap -r less18.req --level 3 --risk 2 --batch-r less18.req: 指定请求文件。--level 3: 检测等级提高到3Sqlmap会尝试对User-Agent和Referer等HTTP头进行测试。--risk 2: 风险等级设为2允许Sqlmap使用一些基于时间的注入测试对于盲注很有用。--batch: 以非交互模式运行所有选择都按默认来适合自动化。指定注入点如果Sqlmap没有自动识别出头部的注入点我们可以用-p参数手动指定。sqlmap -r less18.req -p “User-Agent” --batch这会告诉Sqlmap只对User-Agent头部参数进行注入测试。获取数据一旦Sqlmap确认存在注入点后续的操作就简单了使用--dbs枚举数据库-D security --tables枚举表-D security -T users --dump导出数据即可。工具使用注意事项Cookie与会话确保保存的请求文件(.req)中包含有效的Cookie或Session ID因为登录后的操作需要维持会话状态。如果关卡有验证码或Token机制虽然sqli-labs第十八关通常没有工具自动化可能会更复杂。请求频率Sqlmap默认的测试请求非常密集可能会对靶场服务器造成压力甚至触发潜在的WAFWeb应用防火墙规则。在测试生产环境时务必使用--delay参数设置请求间隔并谨慎评估。理解输出不要只盯着最终的数据结果。多观察Sqlmap的测试过程看它发送了哪些Payload触发了什么样的响应这本身就是学习各种注入技巧的绝佳途径。5. 漏洞防御与安全开发启示作为开发者从第十八关的漏洞中应该吸取深刻的教训。HTTP头注入的本质依然是“不可信数据未经验证即拼接进入SQL语句”。根本的解决方案使用参数化查询预编译语句这是防御SQL注入最有效、最根本的方法。无论是PHP的PDO、Python的sqlite3或MySQLdb、Java的PreparedStatement其原理都是将SQL语句的结构模板与数据分离。数据库先编译语句结构再将用户输入的数据作为纯参数传入从根本上杜绝了数据被解释为代码的可能性。以PHP PDO为例的正确写法?php $stmt $pdo-prepare(“INSERT INTO ua_log (username, uagent, ip) VALUES (:username, :uagent, :ip)”); $stmt-bindParam(‘:username’, $username); $stmt-bindParam(‘:uagent’, $_SERVER[‘HTTP_USER_AGENT’]); // 即使来自HTTP头也安全 $stmt-bindParam(‘:ip’, $_SERVER[‘REMOTE_ADDR’]); $stmt-execute(); ?输入验证与过滤辅助手段虽然参数化查询是首选但对输入进行严格的验证和过滤也是良好的安全习惯。白名单验证对于User-Agent虽然格式多变但可以设定一个合理的最大长度限制如500字符防止过长的注入载荷。转义处理如果因历史遗留问题必须使用字符串拼接强烈不建议则必须对输入进行正确的转义。在MySQL中使用mysqli_real_escape_string()函数。但请注意转义并非万能且依赖于正确的字符集设置容易出错。最小化数据库权限运行Web应用的数据库账户应遵循最小权限原则。例如这个用于记录日志的数据库连接账号可能只需要INSERT权限到ua_log表而不需要SELECT、UPDATE、DELETE权限更不需要DROP、FILE等危险权限。这样即使发生注入攻击者能造成的破坏也有限。安全的日志记录实践对于记录User-Agent这类需求可以考虑在存入数据库前进行标准化处理或哈希处理如果不需要原文查询。或者直接将日志写入文件系统而不是数据库可以避免一类注入风险。6. 常见问题与排查技巧实录在实际操作第十八关时你可能会遇到以下几个典型问题问题1登录失败无法进入后续步骤。排查仔细查看关卡页面的前端代码右键查看源代码有时作者会在HTML注释里给出登录提示。尝试最常见的弱口令组合如admin/admin,admin/password,test/test等。sqli-labs的许多关卡默认密码就是admin。问题2修改User-Agent后页面没有报错一切正常。排查确认注入点你是否拦截了正确的请求登录动作本身可能是一个POST请求而记录日志可能是登录成功后跳转的一个GET请求。确保你测试的是触发记录功能的那个请求。尝试其他头部User-Agent可能被过滤了试试Referer头或X-Forwarded-For头。在Burp Repeater中直接添加或修改这些头部字段。尝试盲注Payload可能关卡设计为布尔盲注或时间盲注。尝试在User-Agent后添加‘ and ‘1’’1和‘ and ‘1’’2观察页面返回内容如标题、某个单词、图片是否有细微差别。或者使用时间盲注‘ and sleep(5) and ‘观察响应是否延迟5秒。问题3报错信息中看不到查询结果只显示部分XPATH语法错误。排查这是updatexml()函数的一个限制。它返回的字符串如果过长在报错信息中会被截断。解决方案使用substring()或mid()函数分段读取。例如要获取所有的用户名可以先查询长度再分段截取 and updatexml(1, concat(0x7e, substring((select group_concat(username) from users), 1, 30), 0x7e), 1) and 然后修改substring的第二个和第三个参数起始位置和长度来获取后续部分。问题4使用Sqlmap测试时总是失败或无法识别注入点。排查检查请求文件用文本编辑器打开你保存的.req文件确保它包含完整的HTTP请求包括Host、Cookie等头部并且请求方法是正确的。指定测试参数明确告诉Sqlmap测试哪个头部sqlmap -r less18.req -p “User-Agent,Referer”。调整Level和Risk尝试提高--level和--risk的值最高分别为5和3让Sqlmap进行更全面的测试。处理Cookie如果关卡有会话验证确保你的请求文件中的Cookie是新鲜有效的。可以先用浏览器正常登录一次再从Burp History里复制最新的请求。问题5注入成功但获取的数据不是想要的用户表。排查information_schema.tables里可能有很多表。你需要根据表名来猜测其用途。在sqli-labs的security数据库中常见的敏感表就是users。如果没找到可以尝试user、accounts、admin等常见表名或者用group_concat(table_name)一次性列出所有表名再仔细筛选。攻克第十八关的关键在于思维模式的转变——将HTTP请求的每一个部分都视为潜在的输入向量。这种“头注入”在现实中的WAFWeb应用防火墙绕过、漏洞拼接攻击中时有应用。通过手工一步步拆解你不仅学会了一个技巧更建立起一种全面、立体的安全测试视角。
延伸阅读

更多相关文章

2026/9/29 1:29:57

深入理解ntohl()函数:网络字节序转换原理与C++跨平台编程实践

1. 项目概述:为什么我们需要关心字节序?在C网络编程或者处理跨平台二进制数据交换时,你很可能遇到过一些“神秘”的函数,比如ntohl()、htons()。我第一次接触它们是在写一个简单的TCP客户端,从服务器接收一个4字节的整…

2026/9/29 12:51:50

痛风饮食安全算法:精准管理海鲜嘌呤摄入

1. 痛风患者的饮食困境与算法化思路作为一个长期与高尿酸作斗争的痛风患者,我深刻理解那种面对美食时的纠结——特别是当一盘新鲜肥美的海鲜摆在面前时。传统饮食建议往往简单粗暴地给出"避免高嘌呤食物"的结论,但实际生活中我们需要更精细的决…

2026/10/4 12:26:20

第19届成图大赛国赛复盘:从CAD建模到创新设计的实战指南

1. 背景与核心概念全国大学生先进成图技术与产品信息建模创新大赛(简称“成图大赛”)是国内工程图学领域最具影响力的学科竞赛之一。它不仅是检验学生制图、建模、创新设计能力的试金石,更是连接高校教学与企业需求的桥梁。然而,随…

2026/10/7 6:50:23

模块耦合Coupling-自考大学-东方仙盟

No-direct coupling 无直接耦合Data coupling 数据耦合Stamp coupling 标记耦合(特征耦合)Control coupling 控制耦合External coupling 外部耦合Common coupling 公共耦合Content coupling 内容耦合Coupling increases from left to right. Module inde…

2026/10/7 6:50:23

【题解-洛谷】P1164 小 A 点菜

题目:P1164 小 A 点菜 题目背景 uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。 uim 指着墙上的价目表(太低级了没有菜单),说:…

2026/10/7 6:50:23

AI应用开发安全方案:五层纵深防御与实战避坑指南

1. AI应用开发安全方案的整体设计思路1.1 为什么AI应用的安全问题比传统应用更棘手做过几年传统Web开发的朋友,第一次接触AI应用开发时,往往会有一个错觉:不就是调个API、拼个Prompt、返回一段文本吗,能有多复杂?我当初…

2026/10/7 6:50:23

OpenShell实战指南:会话管理、插件扩展与AI辅助的现代终端体验

终端工具这么多年,说实话已经进入了一个相对稳定的阶段,很多新项目无非是把老的Scheme换个皮肤,改改快捷键设置,真正值得折腾的并不多。OpenShell这个名字第一次出现在我视野里,是在某个技术社区的讨论串里&#xff0c…

2026/10/7 6:50:22

superpowers效率增强模式:从零搭建自动化工作流实战

1. 从“superpowers”这个热词说起:它到底指什么“superpowers”这个词最近在技术社区和效率工具圈子里被反复提起,很多人第一次看到它是在某个开源项目的讨论区,或者是在朋友转发的一条“效率翻倍”的截图里。它不是一个具体的软件名称&…

2026/10/7 6:45:22

SAW滤波器叉指换能器IDT设计指南:从原理到版图实战

1. 从一块石英片说起:为什么叉指换能器是SAW滤波器的灵魂做射频前端的人,绕不开滤波器这个话题。而只要聊到滤波器,声表面波(SAW)方案就一定会被摆上台面。原因不复杂:它体积小、一致性好、成本可控&#x…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

ESP32免重刷固件:浏览器直接修改NVS键值实现WiFi配置更新

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

SAP HANA查询结果导出CSV:避开乱码、性能与权限的实用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

数字后端Placement阶段Density与Congestion控制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑