一次利用sql通用防注入系统的经历

[ 2008-02-27 11:56:54 | 作者: dklkt ]
字号: | |
前两天,一个跟我比较有关系的网站被操了.虽然看得出来,那个自称的所谓的hacker只拿到了网站后台的权限,改改网站的标题,发发文章而已.webshell都没有拿到。然后我看了那个站,最简单最基本的sql注入而已,管理员的密码是弱口令,md5加密.一点技术含量都没有.也不知道他是怎么想的.

过了2天,发现管理员还没有动静,想想那网站现在也是没什么人在管了。所以进去逛了下,发现是虚拟主机,没有上传组件,难怪那个自称的hacker没拿到webshell。后来又看了下,fso功能正常,后台有数据库备份的地方,又有css文件手动编辑的功能,所以先编辑css文件往里面插入一句话木马,然后通过备份改成asp文件。webshell就拿到了。

发现网站里面乱七八糟,注入点一大堆,几乎所有的参数都没有过滤。汗~~~

本想给它改改的,后来发现工作量太大,干脆搞个通用防注入算了。

这里用的是Neeao的“SQL通用防注入系统3.1 最终纪念版”。在此表示感谢!另外顺便说下,先前用过“3.1 β版”发现有部分缺陷,过滤貌似会漏掉,所以大家用的时候也建议用最终版。

于是在网站的conn.asp文件里加上文件包含,这样就整站都过滤了。

下面给大家看看部分防注入的代码吧。
<%

'--------定义部份------------------
Dim N_Post,N_Get,N_In,N_Inf,N_Xh,N_db,N_dbstr,Kill_IP,WriteSql
Dim aApplicationValue
If IsArray(Application("Neeao_config_info"))=False Then Call PutApplicationValue()
aApplicationValue = Application("Neeao_config_info")
'获取配置信息
N_In = aApplicationValue(0)
Kill_IP = aApplicationValue(1) 
WriteSql = aApplicationValue(2)
alert_url = aApplicationValue(3)
alert_info = aApplicationValue(4)
kill_info = aApplicationValue(5)
N_type = aApplicationValue(6)
Sec_Forms = aApplicationValue(7)
Sec_Form_open = aApplicationValue(8)

'安全页面参数
Sec_Form = split(Sec_Forms,"|")
N_Inf = split(N_In,"|")

If Kill_IP=1 Then Stop_IP

If Request.Form<>"" Then StopInjection(Request.Form)

If Request.QueryString<>"" Then StopInjection(Request.QueryString)

If Request.Cookies<>"" Then StopInjection(Request.Cookies)

Function Stop_IP()
  Dim Sqlin_IP,rsKill_IP,Kill_IPsql
  Sqlin_IP=Request.ServerVariables("REMOTE_ADDR")
  Kill_IPsql="select Sqlin_IP from SqlIn where Sqlin_IP='"&Sqlin_IP&"' and kill_ip=true"
  Set rsKill_IP=killSqlconn.execute(Kill_IPsql)
  If Not(rsKill_IP.eof or rsKill_IP.bof) Then
    N_Alert(kill_info)
  Response.End
  End If
  rsKill_IP.close  
End Function

'输出警告信息
Function N_Alert(alert_info)
  Dim str
  str = "<"&"Script Language=JavaScript"&">"
  Select Case N_type
    Case 1
      str = str & "window.opener=null; window.close();"
    Case 2
      str = str & "alert('"&alert_info&"Http:Www.Neeao.Com\n\nBy:Neeao');window.opener=null; window.close();"
    Case 3
      str = str & "location.href='"&alert_url&"';"
    Case 4
      str = str & "alert('"&alert_info&"');location.href='"&alert_url&"';"
  end Select
  str = str & "<"&"/Script"&">"
  response.write  str
End Function 

'判断注入类型函数
Function intype(values)
  Select Case values
    Case Request.Form
      intype = "Post"
    Case Request.QueryString
      intype = "Get"
    Case Request.Cookies
      intype = "Cookies"
  end Select
End Function 

'sql通用防注入主函数
Function StopInjection(values)
  For Each N_Get In values

    If Sec_Form_open = 1 Then 
      'response.write SelfName
      For N_i=0 To UBound(Sec_Form)
      'response.write SelfName
        'response.write Sec_Form(N_i)
        If Instr(LCase(SelfName),Sec_Form(N_i))> 0 Then 
          Exit Function
        else
          Select_BadChar(values)
        End If 
      Next
      
    Else
      Select_BadChar(values)
    End If 
  Next
End Function 

Function Select_BadChar(values)
  For N_Xh=0 To Ubound(N_Inf)
    If Instr(LCase(values(N_Get)),N_Inf(N_Xh))<>0 Then
      If WriteSql = 1 Then InsertInfo(values)
      N_Alert(alert_info)
      Response.End
    End If
  Next
End Function

'将注入记录记录到数据库函数
Function InsertInfo(values)
  Dim ip,url,sql
  ip = Request.ServerVariables("REMOTE_ADDR")
  url = Request.ServerVariables("URL")
  sql = "insert into SqlIn(Sqlin_IP,SqlIn_Web,SqlIn_FS,SqlIn_CS,SqlIn_SJ) values('"&ip&"','"&url&"','"&intype(values)&"','"&N_Get&"','"&N_Replace(values(N_Get))&"')"
  'response.write sql
  killSqlconn.Execute(sql)
  killSqlconn.close
  Set killSqlconn = Nothing
End Function

Function N_Replace(N_urlString)
  N_urlString = Replace(N_urlString,"'","''")
    N_urlString = Replace(N_urlString, ">", "&gt;")
    N_urlString = Replace(N_urlString, "<", "&lt;")
    N_Replace = N_urlString
End Function

sub PutApplicationValue()
  dim  infosql,rsinfo
  set rsinfo=killSqlconn.execute("select N_In,Kill_IP,WriteSql,alert_url,alert_info,kill_info,N_type,Sec_Forms,Sec_Form_open  from config")
  Redim ApplicationValue(9)
  dim i
  for i=0 to 8
    ApplicationValue(i)=rsinfo(i)
  next
  set rsinfo=nothing
  Application.Lock
  set Application("Neeao_config_info")=nothing
  Application("Neeao_config_info")=ApplicationValue
  Application.unlock
end Sub

'获取本页文件名
Function SelfName()
    SelfName = Mid(Request.ServerVariables("URL"),InstrRev(Request.ServerVariables("URL"),"/")+1)
End Function

%>

    
从以上的代码可以看出,其实通用防注入的原理比较简单,就是把所有客户提交上来的东西都先检查一番,看看有没有sql注入常用到的关键字。如果有的话,采取相应的措施。不过,用这个防注入代码是会带来一个使用上的问题的,大家注意看这几句:
If Request.Form<>"" Then StopInjection(Request.Form)

If Request.QueryString<>"" Then StopInjection(Request.QueryString)

If Request.Cookies<>"" Then StopInjection(Request.Cookies)
特别是Request.Form那个,也就是说,假如管理员发表一篇文章中含有"and",";"等被过滤的关键字的话,那么也会被k掉。这么说,一篇英文文章根本就无法发表了。这个严重影响了网站的正常使用。

所以我将这条语句If Request.Form<>"" Then StopInjection(Request.Form)删掉了。这样就会缓解这个问题。也就是说,对表单都不过滤了。

暂时先写到这吧。

当然,网站的安全性在系统设计的时候就应该考虑,如果等到之后再来修补,那将会是一件非常麻烦的事情。这件事也给了我很大的启发。

最后再次感谢Neeao的这个小工具,给我省了不少力。

  
   
===================无===敌===分===割===线=====================

看到很多朋友留言问怎么解决sql注入的问题。因此打算把本文更新下。

最近帮一个网站修补sql注入漏洞,用了下面的代码。大家可以拿去用。用到的是正则表达式过滤。只需要在一个公共包含的文件里添加下面的代码即可。
'------------------------------------------------------------------------
'通用防SQL注入代码 by dklkt 2009.2
'------------------------------------------------------------------------
If Request.Form<>"" Then StopInjection(Request.Form)
If Request.QueryString<>"" Then StopInjection(Request.QueryString)
If Request.Cookies<>"" Then StopInjection(Request.Cookies)
        
        
Function StopInjection(values)
  Dim L_Get, L_Get2, regEx
  For Each L_Get In values
    L_Get2 = values(L_Get)
    Set regEx = New RegExp
    regEx.IgnoreCase = True
    regEx.Global = True
    regEx.Pattern = "(\bselect\b|\band\b|'|;|\bor\b|\bxor\b|\bunion\b|\bexec\b|\binsert\b|\bdelete\b|\bupdate\b|\bcount\b|\bchr\b|\bmid\b|\bmaster\b|\btruncate\b|\bchar\b|\bdeclare\b)"
    If regEx.Test(L_Get2) Then
      Alert()
      response.End()
    End If
    Set regEx = Nothing
  Next
End Function 
        
        
Sub Alert()
        Dim str
        str = "<"&"Script Language=JavaScript"&">"
        str = str & "alert('由于您提交的内容可能包含危险字符,系统已经禁止本次提交,请求的IP已经被记录 \n\n请确保提交的内容中不包含:单引号|select|and|;|or|xor|union|exec|insert|delete|\nupdate|count|chr|mid|master|truncate|char|declare');history.back(-1);"
        str = str & "<"&"/Script"&">"
        response.write  str
End Sub
[最后修改由 dklkt, 于 2009-02-24 22:44:00]
评论Feed 评论Feed: http://www.dklkt.cn/feed.asp?q=comment&id=81
UTF-8 Encoding 引用链接: 点击查看引用链接

浏览模式: 显示全部 | 评论: 5 | 引用: 0 | 排序 | 浏览: 8705
引用 胡说*
[ 2008-03-10 22:57:38 ]
你这还是没说怎么解决过滤啊,仅仅讲了怎么过滤而已
引用 dklkt
[ 2008-03-11 16:15:38 ]
不明白楼上的“解决过滤”是什么意思。我们这里所说的过滤是指检查用户提交的数据中有没有象select等sql注入语句。如果发现的话,直接将其ban掉。而不是replace之类的。

本文的目的在于讨论:通用防注入系统的缺点——对提交的表单也会检查,从而造成使用上的不便。
引用 jack*
[ 2008-06-24 15:44:18 ]
最近注入很猖狂,我的网站也是这样,禁止and,*的话,文章就没办法发布了,现在有好的解决办法了么期待能在公布以下
引用 dklkt
[ 2008-06-27 10:31:46 ]
其实关键是要在设计的时候考虑到sql防注入。主要就是对于带入sql语句的变量先进行过滤处理。

以下是一种过滤方法的提示。转自邪八。

--------------------
文章作者:勇敢的风 [E.S.T顾问团成员]
信息来源:邪恶八进制信息安全团队(www.eviloctal.com)
<% 
function sql_zr(str) 
dim w,j
str=lcase(str) 
w = "'∥%∥&∥*∥#∥@∥(∥)∥=∥and∥select∥update∥chr∥delete∥%20from∥;∥insert∥mid∥master.∥set∥chr(37)" 
w = split(w,"∥") '22222222 
for j = 0 to ubound(w) 
if instr(str,w(j)) <> 0 then 
response.redirect "../" 
response.end 
end if 
next 
end function 
%>
以前没有限制大小写,现在加上了。

通用的弊端在上一层我已经说了,这里简单说说针对个别的过滤说一下

过滤sql注入时,我们应该过滤那些字段我们应该清楚,就是出现在sql语句中的变量,一般出现在SQL语句中的变量为搜索的时候,有的时候搜索数字,有些时候搜索文字,对于数字我们可以用判断该变量是不是数字即可,对于文字,用上面的代码即可。
代码说明:
if instr(str,w(j)) <> 0 then
找到sql注入后所作的处理
end if

用法,把这段代码放在读取数据库的那个文件,一般为Conn.asp
然后对出现在sql语句中的变量使用该函数即可,如:
sql_zr(request("key"))
[最后修改由 dklkt, 于 2008-06-27 10:32:52]
引用 yzlw*
[ 2009-09-20 14:37:02 ]
谢谢博主,用了你的防注入代码,解决大问题啦!

发表
表情图标
[smile] [confused] [cool] [cry]
[eek] [angry] [wink] [sweat]
[lol] [stun] [razz] [redface]
[rolleyes] [sad] [yes] [no]
[heart] [star] [music] [idea]
UBB代码
转换链接
表情图标
悄悄话
用户名:   密码:   注册?      (游客发言无需密码)
验证码 * 请输入验证码