漏洞挖掘与利用
测试环境的搭建
引言
为什么要搭建本地测试环境?我想下面的东西能够回答你的疑惑。
第二百八十五条 违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的,处三年以下有期徒刑或者拘役。
第二百八十六条 违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的,处五年以上有期徒刑。
违反国家规定,对计算机信息系统中存储、处理或者传输的数据和应用程序进行删除、修改、增加的操作,后果严重的,依照前款的规定处罚。
故意制作、传播计算机病毒等破坏性程序,影响计算机系统正常运行,后果严重的,依照第一款的规定处罚。第二百八十七条 利用计算机实施金融诈骗、盗窃、贪污、挪用公款、窃取国家秘密或者其他犯罪的,依照本法有关规定定罪处罚。
非法入侵他人计算机属于违法行为,但是渗透测试者又需要进行实战训练,所以便有了各种渗透测试平台。这里我们选用WebApp Pentesting作为本地测试环境。
WebApp Pentesting
WebApp Pentesting,由PentesterLab出品。官方给自己的定义是一个简单又十分有效学习渗透测试的演练平台。它提供诸多的漏洞系统以供网络安全发烧友进行测试和让黑阔们更加深刻地且透彻理解“漏洞”。
在开始之前,我们需要先安装虚拟机。我的电脑上已经安装好了VMware,所以我不提供虚拟机的安装教程。然后是下载漏洞集成环境,首先在浏览器中输入https://pentesterlab.com/exercises/web_for_pentester_II
并访问,得到如下的界面。点击其中的Click下载:
点ISO下面的click here下载测试环境操作系统。因为测试环境是集成在一个Linux操作系统中的,所以我们用虚拟机安装,安装过程就不说了。安装好后打开,看到如下的界面:
然后我们输入ifconfig命令查看IP地址,这里安装虚拟机的时候用的是桥接方式:
可以看到IP地址是192.168.1.148,那么我们在浏览器中输入192.168.1.148,打开的界面如下:
如果像这样就说明安装成功了。粗体文本到这里,测试环境的搭建基本告一段落。
SQL注入
引言
为什么要先讲SQL注入呢?我也不知道,可能是我学习时最先接触的是SQL注入漏洞吧!
首先引用百科的定义,如下:
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.
早在02年的时候,国外就已经广泛的使用SQL注入漏洞了,而国内是05年才开始广泛的使用。这么多年过去了,很多网站都通过各种方法补上了SQL注入漏洞,现在还有能够直接利用的SQL注入漏洞少之又少。但并不意味着没有。
SQL注入原理
讲SQL注入原理的时候我主要通过PHP+MYSQL来对其进行讲解(后面也是,除非特别说明)。
简答来说,SQL注入是利用网站程序逻辑漏洞,以达到窃取数据库信息甚至是向服务器写入木马的目的。
在能够访问并操作数据库之前,需要连接到数据库,PHP中使用mysql_connect方法链接数据库:
mysql_connect(servername,username,password);
参数 描述
servername 可选。规定要连接的服务器。默认是 "localhost:3306"。
username 可选。规定登录所使用的用户名。默认值是拥有服务器进程的用户的名称。
password 可选。规定登录所用的密码。默认是 ""。
当PHP脚本执行完毕时会自动关闭数据库链接,当然也可以提前关闭,使用:
脚本一结束,就会关闭连接。如需提前关闭连接,请使用 mysql_close() 函数。
当创建好PHP脚本与数据的的连接以后,就可以使用SQL语句(请参照第一部分中SQL)对数据库进行操作。当然并不是将形如CREATE DATABASE my_db
的SQL语句写入到脚本中,而是通过mysql_query方法进行相应的操作。例如创建一个表:
mysql_query("CREATE DATABASE my_db");
有了以上的基础后就可以开始讲注入原理。现在,我们假设我写编写了一个留言板程序,实现用户留言以及查询和查看留言明细功能。在查看留言明细页面,通过GET请求设置id号来表示要查看的留言的ID号。我们首先创建一个message数据库,在其中添加message表,message表中有id,content字段。现在查看留言明细页面(information.php)的简易版代码如下:
<?php
// php中变量名前有$符号
// 打开数据库连接
$con = mysql_connect("localhost","root","password");
if (!$con) {
die('Could not connect: ' . mysql_error());
}
// mysql_select_db方法用于选择指定名称数据库
mysql_select_db("message", $con);
// 此处的$_GET['id'];为系统定义的变量表示GET请求中的ID属性,对应的也有$_POST
// sql语句表示在message表中查找id等于$_GET['id']的数据并返回其全部字段(*代表全部字段)
$id = $_GET['id'];
$result = mysql_query("SELECT * FROM message where id = " + $id);
// 将刚才返回的所有数据一行一行的输出到屏幕
while($row = mysql_fetch_array($result)) {
echo $row['id'] . " " . $row['content'];
echo "<br />";
}
mysql_close($con);
?>
我们在浏览器中输入如下:
www.xxxx.com/information.php?id=2
返回结果如下:
2 留言测试一下☺
现在注意到其中的查询语句中的SQL语句:
SELECT * FROM message where id =
这里使用的是字符串拼接(PHP中两个字符串可以使用加号链接起来),假设我们的$_get['id']
中的数据是3,那么mysql_query方法接受的参数就是:
SELECT * FROM message where id = 3
注意到这里并没有对$_get['id']
进行判断,也就是$_get['id']
中的数据可能是任意的内容,例如 asdf 那么拼接产生的SQL语句如下:
SELECT * FROM message where id = asdf
这样mysql_query语句将报错。如果$_get['id']
中的值经过精心构造,如 1 and 1=1 那么产生的SQL语句如下:
SELECT * FROM message where id = 1 and 1=1
and 1=1永远为真。可以看到$_get['id']
中的值并不合法,但是SQL执行却正常。如果加以利用,就能获取网站数据库的所有信息,可见其危害性之大。
一般注入流程
我们还是以上面所用的代码来讲一般的注入流程。现在我们在message数据库中加入admin表用于存储网站管理员的账号密码,并在admin表中添加id,username,password三个字段(意义显而易见)。现在我们以攻击者的身份,通过刚才代码中的漏洞来窃取管理员的账号密码。
一般来说,注入流程如下:
1. 注入点的判断;
2. 表名以及字段的猜解;
3. 在网页中显示回显位;
4. 回显数据库中数据;
第一条无需解释。第二条:通过注入窃取数据库的信息其实也和正常的查询语句一样,所以我们需要先知道他的数据库表名和字段名。第三条:查到信息后需要回显在网页上,这样攻击者才能够看得到信息。信息回显之前需要知道网页上哪些位置能够用于显示信息。第四条:请看第三条。
注入点的判断
在判断注入点之前,要先了解一下注入点的不同的类型。注入的点的类型有三种:1、数字型;2、字符型;3、搜索型。为什么会有三种不同的注入点类型?因为在SQL中查询语句分为以下三种:
数字型: SELECT 列 FROM 表 WHERE 数字型列=值
字符型: SELECT 列 FROM 表 WHERE 字符型列=’值’
搜索型: SELECT * FROM 表 WHERE where 被搜索的列 like ‘%值%’
搜索型中的%表示任意匹配。之所以要分为三种不同的是因为我们在构造注入语句的时候会因为注入点的类型不同而采用不同的注入语句。
这里暂时不讲字符类型、搜索类型的东西,等到数字型的讲完在对其进行补充。
就想上面展示的注入语句一样,无论是数字型还是字符型抑或是搜索型,注入点的判断都是一种思想--判断我们构造的语句是否被执行。比如数字型中的
where id = 1 and 1=1
其中的1 and 1=1
是我们够着的数据,但是拼接后的字符串看起来就在ID值后面又加上了一条逻辑语句,如果将其改为1 and 1=2
所形成的逻辑表达式就变成
where id = 1 and 1=2
1=2的值为假,所以and运算的值也为假,那么查询语句就失败了。通过精心构造的注入语句,很轻松的就判断出了网页是否存在注入漏洞。
表名以及字段的猜解
首先介绍exists函数,exists函数用于判断一条查询语句是否能够返回至少一条数据,能够返回则exists返回true,否则返回false。这个函数给了攻击者判断表名和字段名提供了便利。请看下面的例子:
我们在浏览器中输入如下:
www.xxxx.com/information.php?id=2 and exists(select * from admin)
那么拼接而成的查询语句就变成:
SELECT * FROM message where id = 2 and exists(select * from admin)
这里可以看到用exists(select * from admin)代替了刚才的1=1的部分。如果exists中的查询语句能够返回数据,那么整个语句就执行正常,否则出现错误。例如:
SELECT * FROM message where id = 2 and exists(select * from manager)
因为数据库中不存在manager表,所以exists返回false。因此整个语句执行错误。
因此,如果我们猜的表名不正确,那么整个语句就会执行出错,正确则代表不仅存在这个表,而且还能返回数据(即存在数据)。总之可以通过exists函数来判断表单名和字段名是否为我们猜的值。当猜出表单名为admin的时候,就进一步猜字段名称,如下:
SELECT * FROM message where id = 2 and exists(select username from admin)
和猜表名一样,exists中的查询语句能返回数据,那么返回真,否则为假。
通过exists函数,得到了admin表以及其中的字段名id,username,password。现在,就可以进入第三部分。
在网页中显示回显位
order by
order by - 后接字段名,用于对数据库查询语句返回内容进行排序,用法示例如下:
SELECT * FROM message order by id
这条语句的意思是查询message表并按照id值排序后返回。当然,也可以不使用字段名,使用字段名的代号为,即以表中第一个字段为1,逐次增加1。比如表中的字段按照id,usename,password的顺序排列,那么id代号为1,username为2,password为3。那么上面的示例就可以改为:
SELECT * FROM message order by 1
两者完全等价。至于为什么这么用的原因会在后面讲到。
union 连接符
关于union连接符的介绍,一下来自百度百科:
UNION操作符用于合并两个或多个SELECT语句的结果集。请注意,UNION内部的SELECT语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。SQL UNION 语法:
SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2
注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。 SQL UNION ALL 语法 SELECT column_name(s) FROM table_name1 UNION ALL SELECT column_name(s) FROM table_name2另外,UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
这个语句为我们提供了注入时查询数据库信息的途径,当我们在注入点后加入union连接符,只需要前后两个查询语句一致,那么我们就可以任意的查询数据。在构造后面的额查询语句时需要知道前面一个语句的列的数量以及数据类型,而这个工作,就是由前面的order by来实现。
在介绍完基础知识后,就开始判断网页的回显位。想必不用说也能猜到是使用order by加上union来实现网页回显位的判断。要使用union操作之前必须知道前面一个查询语句的列的数量以及数据类型--order by的任务。在order by的部分已经讲到order by用于对数据查询语句返回内容进行排序,并且可以使用对应的数字代替字段名,这使得我们能够直接通过order by + 数字
的方式判断前一个select语句返回的字段数。使用方法就是数字从1开始逐渐递增,直到网页界面返回出错即查询语句出错,也就是说查询语句的字段数小于该数字。看上面代码中的查询语句:
SELECT * FROM message where id = 3
因为message中含有两个字段,ID及content字段,使用*号代表查询所有的字段。所以该语句一共返回两个字段。也就是发送以下系列的请求:
www.xxxx.com/information.php?id=2 order by 1
执行正确,网页返回正常
www.xxxx.com/information.php?id=2 order by 2
执行正确,网页返回正常
www.xxxx.com/information.php?id=2 order by 3
执行错误,查询语句出错,网页返回出错
通过这种方式能够判断出该注入点查询语句返回的字段数位2个。这样我们就可以使用union语句构造查询语句回显信息。
在讲回显位判断之前,还得补充一点select语句的知识。select语句后不仅可以接字段名或*号表示请求字段,还可以使用数字、字符串表示占位回显代替字段输出,比如我们写一个查询语句:
select 1,1,"asdf",2,3
返回结果为:1 1 "asdf" 2 3
这里没有使用from语句,因为这里并没有出现任何的字段名称,出现的都是常量,没有涉及到数据库的查询,所以并不需要指定表。正因为有select的这个特性,才使得判断网页回显位变得十分轻松。比如select后接从1开始递增的数字,那么查询语句返回的结果就是一串从一开始递增的数字,并把它显示到网页上相应的位置。还是以上面的代码为例,我们构造语句如下:
www.xxxx.com/information.php?id=-2 union select 1,2
这里,我在id的值前添加了负号,使前一个查询语句不返回内容来影响对结果的判断。如果我们不加负号,那么上面的结果返回如下:
2 留言测试一下☺
1 2
可以看到1和2分别表示ID和content的显位,如果你喜欢,你也可以使用如下的语句:
www.xxxx.com/information.php?id=-2 union select "First","Second"
不过我觉得这种做法纯属蛋疼,还是直接用数字递增更为直观。那么到这里为止,寻找网页显位的部分也告一段落,下面进入的部分就是回显数据库中的数据。
回显数据库中的信息
其实讲完上面的部分,这一部分已经没有什么好讲的了,如果你够认真,那么你自己也能完成这部分的任务。
上面已经讲到,SQL注入其实也是通过正常的查询语句查询数据库内容,所以欲回显数据库中的信息,必须知道数据库的表名、字段等。上面我们已经猜出了表名和其中的字段(请看表名以及字段的猜解部分),这里我就直接使用。
回显数据库中的信息,需要用到我们上面的显位。相比你已经猜到,用需要回显的内容替换掉select语句中相应的占位符,讲select语句补充完整,就能回显数据库中的信息。使用上面的代码,构造着语句如下:
www.xxxx.com/information.php?id=-2 union select 1,username form admin
www.xxxx.com/information.php?id=-2 union select 1,password form admin
www.xxxx.com/information.php?id=-2 union select username,password form admin
假设admin表中只有一条账号密码都是admin的数据,那么上面语句分别返回如下:
1 admin
1 21232f297a57a5a743894a0e4a801fc3 -> admin的MD5密文
admin 21232f297a57a5a743894a0e4a801fc3
我想已经没有必要对上的内容进行解释了,结果简单直观。到这里为止,简单的SQL注入利用就结束了。当然,SQL注入还有其他部分的知识,其他部分将在后面的部分进行讲解,这里让我们进入实战环节。
第一次实战
打开测试环境的虚拟机,输入ifconfig并查看IP地址(具体请看前面部分)。在浏览器中输入相应的IP地址,这里我的是192.168.1.148,然后看到如下的界面表示成功:
这里有很多的漏洞供读者联系使用,不过此处,请移步到SQL injections中的Example4:
打开后显示如下:
这里的注入点是req=username='hacker',即ID为req,值为username='hacker'。这里的注入点比较特别,其实他是把整个where语句中的部分放到URL中了。通过前面的方法判断为有注入点:
可以看到使用and 1=2没有返回数据,而使用and 1=1返回了数据,说明存在注入点。现在猜表名:
当然这里我是直接使用的正确的数据,至于你们自己实战的时候,就要靠运气了,一般管理员与用户的表名都是形如admin、users、manager之类的组合。下面开始猜解字段名:
通过返回结果得知users表中存在名为username的字段。同理我猜出了还有password这个字段。下面就判断猜前面查询的字段数:
这里就不详细贴过程,不过请看图中我标志的位置,当我增加到第四个时,提示并不存在column 4,这也可以看出1、2、3分别于前面的字段对应。当我们输入4的时候,前面并不存在第四个字段,所以返回错误。下面就是显位的判断:
通过返回的网页数据可以看出,1、2有在网页上显示出来,但是3并没有显示,所以能够直接利用的显位就是1和2。这里注意到前面的数据也有显示,因为我没有让前面的语句执行结果为假,下面的的图片则是前面语句返回假时的情况:
现在就可以直接利用显位来回显我们需要查询的数据,我在图中做了批注,这里就不用讲了。直接上图:
到这里,整个简单的实战就结束了,那么也因该对如何利用简单的SQL注入漏洞有所了解。下面会讲到SQL注入的一些高级方法。
更方便的MySql注入
其他类别的数据库也是使用如上的方法即可进行注入。上面讲的方法的难点主要在猜表名、字段名上。用猜解表名、字段名进行手工注入实在是蛋疼,要是一直猜不出表名的话,基本上可以放弃上面的方法。
对于MYSQL的数据库,如果数据库版本大于5.0,那么有一种更加方便的办法进行注入。因为mysql5.0以上的版本提供了一个名为information_schema的数据库,用这个数据库可以免去猜解表名、字段名的痛苦。
在MySQL中,把information_schema看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名、数据库的表、表栏的数据类型与访问权限等。在information_schema中,有数个只读表。它们实际上是视图,而不是基本表,因此,你将无法看到与之相关的任何文件。
下面对information_schema数据库中的表进行说明:
SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。
STATISTICS表:提供了关于表索引的信息。是show index from schemaname.tablename的结果取之此表。
USER_PRIVILEGES(用户权限)表:给出了关于全程权限的信息。该信息源自mysql.user授权表。是非标准表。
SCHEMA_PRIVILEGES(方案权限)表:给出了关于方案(数据库)权限的信息。该信息来自mysql.db授权表。是非标准表。
TABLE_PRIVILEGES(表权限)表:给出了关于表权限的信息。该信息源自mysql.tables_priv授权表。是非标准表。
COLUMN_PRIVILEGES(列权限)表:给出了关于列权限的信息。该信息源自mysql.columns_priv授权表。是非标准表。
CHARACTER_SETS(字符集)表:提供了mysql实例可用字符集的信息。是SHOW CHARACTER SET结果集取之此表。
COLLATIONS表:提供了关于各字符集的对照信息。
COLLATION_CHARACTER_SET_APPLICABILITY表:指明了可用于校对的字符集。这些列等效于SHOW COLLATION的前两个显示字段。
TABLE_CONSTRAINTS表:描述了存在约束的表。以及表的约束类型。
KEY_COLUMN_USAGE表:描述了具有约束的键列。
ROUTINES表:提供了关于存储子程序(存储程序和函数)的信息。此时,ROUTINES表不包含自定义函数(UDF)。名为“mysql.proc name”的列指明了对应于INFORMATION_SCHEMA.ROUTINES表的mysql.proc表列。
VIEWS表:给出了关于数据库中的视图的信息。需要有show views权限,否则无法查看视图信息。
TRIGGERS表:提供了关于触发程序的信息。必须有super权限才能查看该表。
注意到其中COLUMNS和TABLES,这两个表提供了整个数据库的表名和字段名,而我们注入的时候也正是利用这两个表。
这种更方便的注入方式如下:
1、判断注入点;
2、判断回显位;
3、判断MYSQL版本;
4、如果版本低于5.0,那么使用原来的方法,否则就用简单的方法;
5、通过information_schema.tables得到所有的表名;
6、通过information_schema.columns上得到字段名;
7、通过回显回显信息;
1和2步和上面的教程方法一样,这里不再赘述。当判断出回显位后,使用mysql提供的几个方法判断数据库版本登记本信息:
vesion() 该函数返回mysql数据库版本
database() 用于查看当前数据库名
user() 返回当前用户,即使用者登陆数据库的账号名
这里提前介绍一下group_concat()方法,这个方法可以返回查询字段的所有信息。
找到显位后,用上面的三个方法替换掉相应的显位,记录下显示的信息,稍后会用到:
www.xxxx.com/information.php?id=-2 union select database(),2
www.xxxx.com/information.php?id=-2 union select version(),2
www.xxxx.com/information.php?id=-2 union select user(),2
这里假设的是mysql5.0版本的数据,那么使用version()方法,返回的信息提示等于5.0。然后就可以查看information_schema中的内容,使用方法如下:
www.xxxx.com/information.php?id=-2 union select group_concat(table_name),2 from information_schema.tabls where table_schema="前面database()返回的表名"
这个语句返回database()返回的数据名下的所有表单的名字。然后在返回的表名中找到我们需要的表名。使用下面的语句查找字段名。
www.xxxx.com/information.php?id=-2 union select group_concat(column_name),2 from information_shcema.columns where table_name="想要返回字段名的表名"
这样便省去了猜表名、字段名的琐碎工作。得到表名和字段名后,就是回显数据了,具体方法和上面并无区别,具体请参考上面的部分。请注意, 这个办法仅仅限于mysql数据库,对于其他数据库,请手动猜表名和字段名。
更强大的注入方式
一般的注入方式比较繁琐,需要的条件也比较苛刻。比如,一个注入点没有显位,那么这种办法就不在适用。这里讲另外几种方法,请根据实际情况选择相应的方法。
显错注入
有的时候与遇到无法判断网页显位的情况,但是能够返回数据库错误信息,那么就能够使用显错注入。
显错注入简单来讲就是在查询过程中出现错误,数据库将查询到的部分结果以错误的形式返回给用户。这里讲不会具体的讲解显错注入,因为这个是针对具体的数据库的东西。我仅仅是简单的引入相关的一些知识,拓展视野,等到日后遇到这方面的需求,能够知道有这么一种解决方案在这里,便足矣。
这里我就直接贴上来源于网络的一些文章:
mysql显错注入:
MySQL错误回显套公式法注入
根据mysql报错进行回显注入的原理是什么?
双注入查询
sqlserver显错注入:
SQLSERVER显错注入总结
mssql显错注入:
MSSQL显错模式的手工注入实现原理思考和实战
mssql显错模式的注入手法
这里并没有详细的讲解显错注入的原理,若是不怎么理解,也没多大关系,只需要按照教程上的内容套用公式达到注入的目的即可。等到有一定编程功底的时候,便自然而然的理解了这种注入的原理。
显错注入的例子请看测试平台中injection部分的example7。这里我贴上官方的漏洞教程:课程
盲注
SQL盲注也是一种SQL注入,攻击者可以操纵SQL语句,应用会针对真假条件返回不同的值。但是攻击者无法检索查询结果,这种情况便是盲注的用武之地了。SQL盲注是一种很常见的漏洞,但有时它非常细微,经验不丰富的攻击者可能会检测不到。
现在来构建一个漏洞现场。假设受害者的网站请的是一位经验并不丰富的设计人员编写的网页代码,因为经验不丰富,所以这位Coder为黑客留下了入侵网站的漏洞。这位Coder也是一位技术爱好者,深知直接将数据库错误信息反馈给用户是一件极度危险的事情,所以在编写这个网页的时候他采用了下面的方式来处理错误信息。
如果发现数据库执行查询语句的时候出现了错误,就直接跳转到首页。比如,对该网页发送如下的请求:
正确访问时输入的是如下的URL:
www.xxxx.com/find.php?id=1
现在进行非法访问:
www.xxxx.com/find.php?id=injection
错误访问时,浏览器跳转到了
www.xxxx.com/index.php
这个页面。
攻击者一看,处理了错误信息。是不是堵住了注入漏洞?攻击者便使用方法进行验证,他在URL中输入如下内容:
www.xxxx.com/find.php?id=3-2
发现网页返回正常,说明了3-2被数据库解析成为了1,表明了存在注入点。注意到这里的减号,他使得网页构造的数据库查询语句如下:
SELECT * FROM tables WHERE id=3-2
这里执行查询语句的时候将对3-2进行运算并返回结果1。当然你也可以用加号,但是要注意互联网工程任务组(Internet Engineering Task Force,IETF)曾在RFC 2396(统一资源标识符(Uniform Resource Identifier,URI):通用语法)中声称,加号(+)是URI的保留字,需要进行编码。可以用%2B代表加号的URL编码。
也就是说,如果查询语句正确执行了,返回的结果就是正常的,否则就会跳转到主页去。通过上面的方法,我们发现这位Coder虽然想通过不返回错误信息给用户来防止SQL注入,但是注入点依然存在。有心的黑客们很快便找到了这种漏洞的注入方法,这种方法手工操作起来十分麻烦,大多数情况下是使用一些写好的脚本程序或者注入工具进行注入。不过,理解其原理,了解其过程才能更好地使用相应的一些工具。
盲注的内容繁多,不同的数据库操作方法也有差别,这里就简答的以MYSQL为例进行讲解,其余数据库请GOOGLE。
(若是仔细斟酌,会发现下面的内容与上面并不完全衔接,也不必放在心上,了解用法即可。)一般会使用到盲注的情况是没有显位,而这里也仅仅针对这个情况进行讲解,至于盲注更高级的应用,请移步GOOGLE。这里的方法主要是用过逻辑运算加上猜解,如果猜对了,逻辑运算返回正确,否则返回错误。现在假设我们已经猜到了表名admin以及字段名password。由于网页没有回显位,所以我们现在使用猜解的方法进行判断数据库内部信息。首先讲到的是length()、substr()和char()方法:
length() 返回指定数据的长度。
substr() 返回指定数据中的部分数据。substr方法有三个参数,第一个是数据,第二个是指定开始返回的位置,第三个是返回的长度。
char() 接收一个数字,并返回其对应的ASSCII字符。
对于这三个函数如果有不懂得地方请参考MYSQL手册。这三个方法便是攻击者使用的利器,对于上面的网站,这里想要查询其admin表中的password字段中的数据,于是构造如下额请求:
www.xxxx.com/find.php?id=1 and (select length(password) from admin) > 30
将password作为length的参数,返回的password中数据的长度与30做比较,根据返回判断数据其长度为32。至于怎么判断?猜呗,想要快一点的话使用二分查找吧。现在就开始猜数据内容:
www.xxxx.com/find.php?id=1 and (select substr(password,1,1) from admin) = char(56)
这里对password返回的结果进行判断,其第一个字母是否等于56所对应ASSCII字符。如果不等于,就继续猜。等于便使用substr(password,2,1)猜下一个字母,依次类推,知道猜出所有的数据。
当然,盲注的魅力并不仅限于此,还有更高级的用法,这里便不引入了。如果觉得我的讲得并不是非常好,可以参考下面的文章。
延时注入
这个玩意我也没用过,不过从百度上得到的资料上看来,一般和其他注入方式混合使用。具体还是百度吧。
其他有趣的方法
占上位置,以后找到后补充。先贴上乌云的一片文章:利用insert,update和delete注入获取数据
防注入绕过
有注入就有防注入,面对防注入系统,先驱们已经找出了很多办法进行绕过。这里我简单的讲一个初级的绕过方式,至于一些复杂的方式,网上已经出现的教程讲解的胜过我千百倍,所以我将直接贴上他们的文章。
cookie注入
还是讲那个经验并不丰富的程序员的事,公司发现网站被黑后马上修改了代码,这个工作自然还是落到了程序员身上。可怜的程序员想了很久,想到了一种防注入的方式,对用户提交的数据先进行验证,然后才进行查询。为此,程序员写了一个Check()
函数进行判断提交数据合法。并通过该函数返回值判断是否继续。在该函数中,程序员对用户提交的GET和POST请求都进行了判断。因此,网站一段时间内没有被黑。
毕竟是缺少经验的程序员,很快边有人想到了方法对检测进行绕过--cookie(请看前面基础知识部分)注入。
任意打开一个网站,在导航栏中输入如下语句:
javascript:alert(document.cookie);
回车执行,对话框中显示的便是该网页的Cookie值。这是一个javascript语句,alert()用于将传入的参数值显示在一个对话框上(具体百度)。document.cookie返回当前网页的Cookie值。而Cookie注入就是把注入语句写到Cookie中,再提交请求。例如:
www.xxxx.com/find.php?id=1
上面是正常的网页请求,然后我们在导航栏中输入如下的代码:
javascript:alert(document.cookie += "id=" + escape("1"));
用加等于表示的是保留原有Cookie值,后面的内容是ID=1,escape()函数则是对其中的字符串进行编码(具体请百度)。然后又在导航栏中输入如下:
www.xxxx.com/find.php?
注意其中的?不要省略。
上面两次请求返回的是同一个界面,说明已经争取的将原本在URL中的参数写入到COOKIE中并且正确的被解析了。至于注入语句,则插入到escape("1")
中1后面(其实就是多了一步写入Cookie,具体和前面讲的注入方式一样。)即可。
现在,你已经学会了用Cookie绕过防注入的方式了。这里偷一下懒,直接使用网上的实例:纯Cookie手工注入。
当然,随着时间的推移,用这种办法黑掉这个网站的人多了起来,被公司经理骂了一顿以后的程序员加班补上了漏洞,验证了Cookie,So 这个方法也失效了。
深入了解SQL注入绕过WAF和过滤机制
我觉得我写的始终没有网上的好,所以我就直接引用了:深入了解SQL注入绕过waf和过滤机制
至此,SQL注入的内容就告一段落,现在你学到了什么呢。目前应该能够轻松搞定测试环境中的Sql injections了吧。
文件上传漏洞
引言
大多数网页都有文件上传的功能(比如设置头像等),这是网页功能更加个性化,也为渗透者留下后门提供便利。一般来说渗透者在黑网页的时候会尽量拿到WebShell,为后期的提权(请看基础部分)做好准备。下面引用百度百科WebShell词条:
WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称做为一种网页后门。黑客在入侵了一个网站后,通常会将这些asp或php后门文件与网站服务器WEB目录下正常的网页文件混在一起,然后就可以使用浏览器来访问这些asp或者php后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载文件,查看数据库,执行任意程序命令等)。
简单的讲WebShell就是网页后门,想要拿到Shell,有两种办法。一、直接在服务器上写入Shell;二、将本地做好的WebShell提交到服务器上。第一种灵活性比较大,也需要有一定的经验。第二种则是通过上传漏洞达到目的。
文件上传漏洞原理
网页设计有一条原则是不信任任何用户输入,只接受合法的用户输入。只有这样才能够保障安全性。文件上传漏洞的产生正是因为程序验证上的逻辑缺陷,比如上传头像的时候并没有判断用户上穿的是否为图片,导致可以上传任意格式的文件,从而使得渗透者轻轻松松拿到WebShell。
利用方法
这种漏洞的利用方法就是通过各种方式利用验证缺陷甚至是绕过验证缺陷。下面讲各种验证方式的绕过方式。
本地Javascript验证
应用程序在本地的Javascript验证文件名是否合法,但是在服务器端并没有做相应的验证,只有在文件名合法的情况下才会把数据发送到服务器。这是最简单的验证方式,很容易绕过。这需要几个条件,首先要Javascript验证合法,然后发送到服务器数据又是我们想要的即可,也就是只需要将文件合法的命名,并抓包上传(brup suite),在包里将文件后缀该为想要的后缀,就能达到我们想要的结果。
抓包上传:当浏览器发送HTTP请求(请看基础知识部分)时,将请求拦截下来,修改里面的数据后重新发送。
这种漏洞几乎灭绝了,如果能遇到,那运气一定是非常之好。当然,还有更简单的利用方式,自己写一个不验证的表单,然后提交到相应的网址,即可达到绕过的目的。
服务端也有简单的验证
服务端应用程序也对文件后缀做了要求,那么久只能够上传合法的(服务器指定的文件后缀)文件。或许读者会觉得如果服务端都限制了文件后缀,那么还有漏洞吗?答案是肯定的。这里就要介绍另外一个漏洞:文件名解析漏洞。
文件名解析漏洞的原理是服务器组建(apache、IIS,请看基础知识部分)等在解析脚本文件时将非脚本文件解析为脚本文件的漏洞。由于依赖组建,不同的组建解析漏洞不同,有的组建没有解析漏洞,所以我就不一一将每种漏洞。解析漏洞总结 - 乌云这篇文章总结了一写常见的解析漏洞及其利用方式。
有了解析漏洞后,在IIS6.0下,我们只需要将脚本命名为shell.asp;.jpg便能够绕过图片验证。
所以对于这种验证方式需要满足解析漏洞这个条件,才能拿到Shell。
服务端对数据内容进行验证
服务端应用程序会将相应的文件进行验证是否合法,只能够上传合法的文件。这里又要牵扯到文件格式的问题,一般的文件如JPG、PNG都会在文件头以几个特殊的字符标志文件类型,如JPG文件头为FFD8FF所对应的ASCII码。服务器如果只是简单地验证一下是否有相应的文件头,那么我们也只需要使用HEX编辑器在Shell代码前写入相应的文件头即可绕过。
有时候服务器会验证用户上传的图片是否是一个真的图片,及图片能否正确显示。这样我们就不能通过简单的添加相应的文件头来绕过检测系统。既然需要真实文件,那么我就就把代码加到真实文件的后面去即可。
当然这个和恰免得一样,是需要解析漏洞来帮助执行的,没有解析漏洞,那么就没有实际意义。
服务端没有解析漏洞怎么办?
如果服务端没有解析漏洞,那么前面的方法统统失效,即无法通过shell.asp;.jpg这种方式将文件解析为脚本。似乎这样服务器的安全性就很高了,实则不然,因为最终文件命名还是通过操作系统,而编写操作系统主要使用的都是C语言,C语言中以'\0'作为字符串结尾。想必这里已经有人能够猜到如何突破这种限制。因为脚本语言实现方式与C并不一样,所以'\0'并不是脚本语言结束符。
针对这种验证方式,出现了00截断上传。所谓00截断上传,是指通过抓包,将文件名改为shell.asp00.jpg的形式,让服务器生成文件时将文件命名为shell.asp。这里修改00并不是直接输入00,需要将其编码为L'\0'(宽字符)。(具体请百度)
需要注意到的是上面的几种方式都是在服务器允许出现多个.,并且没有修改文件名的状态下成立的。如果服务器要求有且仅有一个.,或者将上传文件命名为时间假后缀的方式,上面的方法统统失效。对于这种情况,我也没有什么好的办法拿到Shell。
目前为止,已经科普完了文件上传漏洞及其利用方式。由于精力有限,所以没有涉及到具体的操作细节,希望结合百度、谷歌,定能事半功倍。
XSS
XSS是这种技术恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。XSS攻击分成两类,一类是来自内部的攻击,主要指的是利用程序自身的漏洞,构造跨站语句。另一类则是来自外部的攻击,主要指的自己构造XSS跨站漏洞网页或者寻找非目标机以外的有跨站漏洞的网页。如当我们要渗透一个站点,我们自己构造一个有跨站漏洞的网页,然后构造跨站语句,通过结合其它技术,如社会工程学等,欺骗目标服务器的管理员打开。
XSS的技术博大精深,像qq空间、微博等都存在XSS漏洞,可以想象其威力。这方面我也不太会,所以引用了他人的文章。
XSS原理与分析1
XSS原理与分析2
XSS原理与分析3
XSS原理与分析4
花样XSS
CSRF
和XSS一样,我也只是了解了个皮毛,所以直接贴上百度百科:
CSRF(Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者session
riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
至于教程嘛,引用大牛写的吧:
其他漏洞
除了上面的几种漏洞以外,这里还有几种漏洞也是非常受到渗透者的喜爱。常见的有文件包含漏洞、文件下载漏洞、越权访问漏洞、命令执行漏洞。这些漏洞都越来越少了,所以这里只是简单引入,并不做讲解,具体可以百度相关信息。
至此,漏洞部分的内容基本结束,在漏洞挖掘过程中,应当注重积累,细心、耐心,就能