有好多人都只知道有sql注入漏洞这种漏洞,也知道怎么用一些工具来利用漏洞,但是却不知道SQL注入漏洞的原理。为了帮助初学者理解sql注入的原理,我写下了这篇文章,希望能对大家有所帮助。
什么是SQL注入:
SQL注入是攻击者通过把恶意SQL命令插入到Web表单的输入域或页面请求的查询字符串中,来达到欺骗服务器执行恶意的SQL命令的一种攻击方式。(数据与代码没有完全分离)
Sql注入漏洞产生原理:
上面我们提到SQL注入的产生原因是数据和代码没有完全分离产生的。下面我们来看看SQL注入漏洞具体的产生过程:
首先,我们来看看浏览器浏览链接时的工作原理。
在我们打开某一个链接的时候浏览器和服务器是存在交互的。这个链接中存在着服务器需要为浏览器提供的数据内容的查询名称。比如www.123.com/news.index.asp?id=1(假想地址),这里,当浏览器提出访问请求的时候,服务器就会在数据库中查找id=1的数据,然后反馈给浏览器,这样,我们浏览器就能根据服务器反馈的数据来满足浏览者的需求。查找的代码如下图所示。
按理说,这个过程是挺巧妙的吧。但是,如果你在网站代码编写的时候没有将数据与代码分离的话,这个过程中就存在着漏洞。
在数据库查询过程中,实际执行的语句如下:
Select *from news where id=1
现在我们在URL(http://www.123.com/news.index.asp?id=1(假想地址))后面添加"and 1=1",此时实际执行的SQL语句是:
Select *from news where id=1 and 1=1
由于这个条件永远成立,所以返回的页面和正常页面相同。
当添加“ and 1=2”时,会执行如下SQL语句:
Select *from news where id=1 and 1=2
由于这个条件永远不成立,所以返回的页面和正常页面不同。
现在我们可以控制参数id的值来影响程序的返回结果。我们来分析一下上面图中的代码,后台在通过GET方式取的参数id的值后,直接用来构造动态SQL语句,并执行SQL查询。这整个过程没有对变量id的值作任何处理。这就导致了SQL注入漏洞的产生。(其实,这个漏洞我们如果在写网站代码的时候将数据与代码分离,那么这种漏洞完全可以避免。不过由于一些程序猿的代码编写问题,这种漏洞在网站里还是很常见。)
Sql注入漏洞的判断:
我们上面讲了sql注入漏洞,那么到底怎么判断一个网站到底有没有sql注入漏洞呢?
首先,注入是有一定前提条件的。那就是我们的目标一定是动态的,存在数据库交互的web系统。如果不是动态的话,大家还是洗洗睡吧,别往sql注入方面想了。(我刚接触sql注入的时候看过别人拿工具去试一个静态站点。。。。)
我们的注入类型有字符型注入、整型注入和搜索型注入。
我们判断是否有sql注入漏洞的时候也是针对这三种注入类型来判断的。
字符型注入漏洞的判断:
字符型注入漏洞的判断就是我们常见的单引号探测。
在我们的判断目标后加一个单引号,如果目标回馈一个异常界面,就说明它没有进行字符型过滤。这样,我们就可以判断这里很可能存在字符型注入漏洞。
×××注入漏洞的判断:
对于×××注入漏洞,我们使用and探测。比如
http://www.123.com/news.index.asp?id=1 (1)
我们在它后面加上and 1=1,
即http://www.123.com/news.index.asp?id=1 and 1=1 (2)
看它的加载情况是否与原来的网页的加载相同。然后我们在(1)的后面再加上and 1=2
即http://www.123.com/news.index.asp?id=1 and 1=2 (3)
然后加载。如果(1)与(2)的加载情况相同而(3)与(1)(2)的加载情况不同,我们就可以判断此处存在×××注入漏洞。
搜索型注入漏洞的判断:
搜索型注入漏洞的判断与×××注入漏洞相似,都用到了and 1=1 和and 1=2。下面,我们来介绍下怎么判断搜索型注入漏洞吧。
首先,我们在搜索框中输入1%’and 1=1 and ‘%’=’,点击搜索,查看搜索结果。
然后,我们在搜索框中输入1%’and1=2 and ‘%’=’ ,点击搜索,查看搜索结果。
如果我们两次的搜索结果不一样的话,那就说明此处存在搜索型注入漏洞 。
介绍搜索型漏洞的一篇文章:
http://blog.guetsec.org/?p=85
有的人在探测sql注入漏洞的时候只用到单引号探测,单引号探测探测不到漏洞的话他就认为这里没有漏洞。但其实,对sql注入有一点了解的程序猿他会在这里对字符型进行过滤,让你单引号探测的时候探测不出来。所以我们在判断是否存在sql注入漏洞的时候最好还是把这三种漏洞全部探测完再下结论。
各类型注入的利用原理:
×××注入:
ID=49 这类注入的参数是数字型,SQL语句原貌大致如下:
Select * from 表名 where 字段=49
注入的参数为ID=49 And [查询条件],即是生成语句:
Select * from 表名 where 字段=49 And [查询条件]
字符型注入:
Class=武汉 这类注入的参数是字符型,SQL语句原貌大致概如下:
Select * from 表名 where 字段='武汉'
注入的参数为Class=连续剧' and [查询条件] and ‘'=' ,即是生成语句:
Select * from 表名 where 字段='连续剧' and [查询条件] and ‘'=''
搜索型注入:
搜索型注入利用的是网页在搜索时没过滤参数的漏洞,如keyword=关键字,SQL语句原貌大致如下:
Select * from 表名 where 字段like '%关键字%'
注入的参数为keyword=' and [查询条件] and ‘%25'=', 即是生成语句:
Select * from 表名 where字段like '%' and [查询条件] and ‘%'='%'
手工注入的步骤:
A) 找注入
B) 确认注入
C) 收集信息(服务器名,数据库版本,安装目录等)
D) 爆数据库
E) 爆表段
F) 爆字段
判断web系统的数据库类型。
判断acess数据库和sqlserver数据库:
不同的数据库的函数、注入方法都是有差异的,所以在注入之前,我们还要判断一下数据库的类型。一般 ASP 最常搭配的数据库是 Access 和 SQLServer,网上超过 99% 的网站都是其中之一。而PHP网站一般搭配MYSQL数据库。
大部分情况下,sql漏洞检测的时候会显示数据库类型,但是如果sql漏洞检测的时候网站没有显示数据库类型,我们又该怎么办呢?
我们可以从 Access 和 SQLServer 和区别入手,Access 和 SQLServer 都有自己的系统表,比如存放数据库中所有对象的表,Access 是在系统表 [msysobjects ]中,但在 Web 环境下读该表会提示“没有权限”,SQLServer是在表 [sysobjects] 中,在 Web 环境下可正常读取。
区分MSsql数据库和Acess数据库:
在注入点后加上: ;–(一个分号,两个横线)比如这个网址
www.123.com/news.index.asp?id=1,我们事先已经确定了它是注入点了, 这样的话我们就可以在后面加上;–让它变成
www.123.com/news.index.asp?id=1;– 提交这个网址,如果页面返回正常的话,说明数据库是MSSQL。因为在MSSQL数据库里,;和–都是存在的,”;”用来分离两个语句,而”–“就是注释符,在它后面的语句都不执行。而ACCESS数据库里没有。所以如果是ACCESS的数据库,当你在注入地址后面加上”;–“的话那程序就会把”;–“当成参数的一部分,这样查询就会出错。如果错误,那基本上可以肯定是ACCESS了(因为网上用这两种数据库的网站最多。)
用以上方法都判断不出来的话,那就利用ACCESS和MSSQL数据库的差异来进行判断。要用到两个查询语句。同样,如果注入点是www.123.com/news.index.asp?id=1,那我们在后面加上 and exists (select count(*) fromsysobjects),那么地址就变成了
www.123.com/news.index.asp?id=1 andexists (select count(*) from sysobjects)。如果页面正常返回,那就可以证明数据库是MSSQL的。如果返回正常,就说明存在sysobjects这个表,因为这个表MSSQL数据库里有而ACESS数据库没有,所以可以确定数据库的MSSQL的。如果返回错误,那就不是。那我们怎么用查询语句来判断数据库是不是ACCESS的呢?我们在注入点后加上 and exists (select count(*) frommsysobjects)。就成了www.123.com/news.index.asp?id=1 andexists (select count(*) from msysobjects),按刚才理解MSSQL数据库的方法去理解这条语句。这里要注意,提交这个语句是不会返回正常页面的。就算是ACCESS数据库也不会返回正常的页面。因为默认情况下,我们是没有权限查询这个表里的数据的。不过WEB会提示我们 “记录无法读取;’msysobjects’没有读取权限”。如果返回的是这个错误信息的话,那就证明是ACCESS数据库了。简单地来说就是两条查询语句:
and exists (select count(*) from sysobjects)
and exists (select count(*) from msysobjects)
如果第一条返回正常,那就是MSSQL数据库,如果两条都不正常,那就是ACCESS数据库了。
手工Sql注入:
前面我们在这个网站已经发现了注入点并且确认注入,现在开始接下来的分析。
收集信息:
从这里我们可以看出一下几点:
1、网站使用的是Access数据库,通过ODBC引擎连接数据库,而不是通过JET。
2、程序没有判断客户端提交的数据是否符合程序要求。
3、该网站采用ASP脚本。
接下来就是分析数据库里面的东西了。
猜表名:
用到的语句:and exists(select count(*) from 你要猜的表名) 。在注入点后加上这句话,如果返回正常,说明你猜的表是存在的!比如
www.123.com/news.index.asp?id=1 andexists (select count(*) from admin),如果返回正常,说明admin这张表存在。如果返回错误,就说明不存在。别的表也都是这么猜.
这里我们猜的user表存在。
常用的表名:admin usernews manage a_admin x_admin m_admin adminuser admin_user article_adminadministrator manager member memberlist users Manage_User user_infoadmin_userinfo login new用户会员
然后接着猜列名:
用到的语句:and (select count(列名) from 猜到的表名)>0 。在注入点后加上这句话,如果返回正常,说明你猜的列是存在的!比如
www.123.com/news.index.asp?id=1 and(select count(username) from admin)>0,如果返回正常,那username这个列就存在。不过首先要确定from后面跟的表名要是存在的哦,不然你怎么猜都是错的。
所猜字段名存在。
常用的列名:username password id adminusername admin_username adminname admin_nameadmin adminuser admin_user user_name user_admin administrator administratorsadminpassword admin_pwd adminpass userpass user_pass admin_passwod 用户用户名密码帐号
检测记录数:
用到的语句:and (select count(*) from 猜到的表名)>X (X是个数字)。在注入点后加上这句话,并不停地变换X这个数字,直到猜到准确的记录数为止。比如www.123.com/news.index.asp?id=1 and(select count(*) from admin)>2 ,这个句子是猜admin表里有几条记录的,也就是有几个管理员(一个管理员对应一条记录)。如果返回正常,说明admin这张表里的记录数大于 2。这个时候我们把2改成别的大一点的数。比如5,如果返回错误,说明管理员的个数在2和5之间,2和5之间的整数是3和4,这个时候我们变换语句为www.123.com/news.index.asp?id=1 and(select count(*) from admin)=3或者=4,哪个返回正常那管理员的个数就是哪个。如果提交>5还返回错误,那就再取一个更大的数,再重复刚才的动作就可以猜到记录数。
检测字段长度:
用到的语句:and (select top 1 len(列) from 表)>X (X和刚才一样。)。select top 1是查询第一条数据的意思(在WEB环境下不支持多行回显,只是一次查询的数据不能超过一行。),len是MSSQL里的一个函数,用法是len(), ()里可以是字符串也可以是表达式也可以是列名。
这里检测字段长度和检测记录数都可以可以采用了“二分查找法”,这样可以减少判断次数,节省时间。如果采用从order by 1依次增加数值的方法来判断,需要8次才可以确定字段数,采用“二分查找法”只需要5次就够。当字段数很大时,二分查找法的优势更加明显,效率更高。