首先是外网爆破获取了PostgreSQL(9.1.24)的管理员账号密码,想通过UDF提权的时候却发现针对Windows平台网上没有编译其dll的教程,我找到的文章都是编译linux平台下.so的UDF。
最终经历种种挫折终于编译成功,并获取到了目标权限,由于比较有意思并且可以弥补部分互联网上关于此内容的空白,因此记录了下来。
首先尝试一个CVE漏洞:
# 删除并创建用于保存系统命令执行结果的表
然而目标并不存在此漏洞,接着我尝试了使用sqlmap自动udf提权:
python sqlmap.py -d "postgresql://postgres:123456@114.114.114.114:5432/postgres" --os-shell
最后无论是选择32-bit和64-bit都无法完成自动udf执行命令,不过得到了两个有用信息:
1、数据库版本:9.1.24
2、目标系统:Windows
当sqlmap自动无法完成的时候我想到了自己手动从sqlmap中提取dll然后写入到目标系统中再创建恶意函数,看看会发生什么,当打开sqlmap的时候我发现sqlmap中只有32位的dll,并且还只到9.0版本,并没有档期目标这个版本的:
只能试试再说了,于是我决定用32位的9.0版本dll做实验,至于如何把dll导入到目标系统中并创建恶意函数,参考:https://github.com/No-Github/postgresql\_udf\_help
不过要注意该工具生成的sqlcmd.txt内容也是针对linux的,要把下面的/tmp/testeval.so的路径改为dll路径,并且该路径需要postgresql拥有权限:
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/testeval.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
我在将32位的9.0版本的dll导入的时候报了not a valid Win32 application错误,我认为此处是由于架构不对导致的,目标PostgreSQL为64位:
我在网上找了很久,都没有发现64位的9.1.x版本的PostgreSQL udf的dll。而关于编译,都是关于linux用gcc编译的,步骤大致为:
1、安装PostgreSQL相关的库(linux可以用apt-get等完成)
2、gcc命令行编译(gcc -Wall -I/usr/include/postgresql/11/server -Os -shared lib_postgresqludf_sys.c -fPIC -o lib_postgresqludf_sys.so)
费劲九牛二虎之力在Github上找到了一个编译PostgreSQL Windows Dll的工程:https://github.com/rop-la/PolyUDF
VS打开之后很多地方爆红,报错找不到postgres.h等包,那么问题又来了,linux可以用apt-get安装,Windows该怎么装呢?我觉得把官网所有的安装包下一遍应该会有答案。
最后我选择官网下载了一份免安装的PostgreSQL的二进制包文件:postgresql-9.1.24-1-windows-binaries.zip(https://www.enterprisedb.com/download-postgresql-binaries) 该包解压后存在各种我们需要的.h头文件:
然后我们需要做的就是将这些.h导入到vs的项目中,选择:项目->PolyUDF属性->VC++目录,在包含目录中添加上.h的目录,总共需要添加3条才不会报错:
C:\Users\xxxxx\Downloads\postgresql-9.1.24-1-windows-binaries\pgsql\include\server
然后由于我不太想用这个项目的c文件编译成dll,因为我没测试过,为了稳妥还是选择了网上最喜闻乐见的lib_postgresqludf_sys.c,这个文件在https://github.com/No-Github/postgresql\_udf\_help有。
将lib_postgresqludf_sys.c的内容粘贴到main.c中,注释掉一些会报错但不影响执行命令的代码,得到main.c,小伙伴们直接用就行了。
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
然后还要注释掉pg_config_os.h的201行到215行两个结构体,因为这里也会报错,然后再编译release->x64即可。中间有个小插曲,如果你的vs报错,无法打开输入文件postgres.lib,那么请将PostgreSQL zip包中的postgre.lib文件复制到项目文件夹中和main.c同目录的位置再编译。
生成的dll在PolyUDF-master\x64\Release\PolyUDF.dll,然后再执行:
cat PolyUDF.dll | xxd -ps | tr -d "\n" > 1.txt
将sqlcmd.txt里面的so路径替换为想要将dll保存到目标系统路径的位置(c:\windows\temp\test.dll或其他位置都行,只要目标postgreSQL有权限)
然而问题又来了,postgreSQL报错The specified module could not be foud。我一开始以为是不是dll的代码有问题,后来我看了代码感觉应该没问题,因为我之前注释的内容都不是我要用的导出函数。那问题出在哪呢?此时我突然想到了之前编译免杀马在不做静态编译时无法在其他人电脑上正常运行的情况。于是我们选择使用静态编译试试。
选择在静态库中使用MFC:
最后生成了一个100k的dll,而之前的dll才16k,然后再用该dll生成sqlcmd.txt,最后sqlcmd.txt内容如下:
SELECT lo_create(5022);
和之前一样把sqlcmd.txt中.so路径改成.dll路径放到PostgreSQL里面执行即可,最后成功Getshell:
最后总结出来感觉很简单,不过自己在试错过程中并不是每一次都能正确猜到错误点在哪里的,所以花了挺多时间,不过最后还是搞定了,可喜可贺,难拿的shell是最值得学习的。