对于经常玩SQL Injection的朋友来说,对于字符的猜解,通常是一件枯燥、乏味、痛苦的事情,特别是中文字符的探测。一遍遍的输入,然后又一次次的被否决。不过,据说这对于耐心的培养是一个非常好的办法。这时,你有没有想过自动注入呢?请看我写的文章SQL Server数据信息自动探测。(做个广告,别扔鸡蛋,不然我今天晚上就不用吃饭了。)
SQL Server中的汉字猜解
在SQL Server中,中文的ASCII为正数,但由于是UNICODE的双位编码,不能用函数ascii()取得ASCII码,必须用函数unicode ()返回unicode值,再用nchar函数取得对应的中文字符。
在探测出SQL Server中的汉字的Unicode编码后,如何知道相应的汉字呢?用工具,我现在没有找到。经过研究,我找到了3种解决办法。
1.在注入地址后添加“and nchar(猜解汉字的unicode编码)>0”,例如:http://www.xxx.com/id=1 and nchar(20013),由于nchar()函数返回值类型为nvarchar,拿一个 nvarchar的值跟int的数与0比较,系统会先试图将nvarchar的值转成int型。当然,转换的过程中肯定会出错,SQLServer的出错提示是这样的:
Microsoft OLE DB Provider for ODBC Drivers 错误 ’80040e07’
[Microsoft][ODBC SQL Server Driver][SQL Server]将 nvarchar 值 ’中’ 转换为数据类型为 int 的列时发生语法错误。
2.使用SQL Server。所谓的“解铃还需系铃人”,可能就是这个道理吧。通过SQL Server的查询分析器、或者企业管理器,我们构造查询条件select nchar(20013),执行查询操作,看到查询结果了吗?
3.使用字符对照表。这是本文的重点,也是SQL Server自动注入中必须解决的一个重要课题。
我们知道,任意一个汉字的Unicode编码是唯一的,其GB18030码也是唯一的,不然的话同一个编码表示N多汉字,你知道是什么吗?那么同一个汉字的Unicode编码和GB18030码有什么关系呢?相等?那还用这么麻烦吗,直接转化成汉字不就得了。我们暂且不管它们之间有什么关系,也不用知道有什么关系,只要清楚同一个汉字有唯一的Unicode编码,其对应的GB18030码也是唯一的就可以了。也就是说,知道了一个汉字的Unicode编码,可以唯一对应一个GB18030码,通过GB18030码,现在我们就可以查找出原来的汉字了。
关于Unicode与GB18030对应码表,你可以在http://www.uighurlinux.org/download.htm 下载。这个Unicode与GB18030对应码表是十六进制的,而且也没有相应的中文字符,不过我们能把GB18030转化成为中文字符。
下面我们的任务就是把这个Unicode与GB18030对应码表为我所用,转换成为Unicode- GB18030-汉字对应表。这儿我要说明一点,对于四位的GB18030码,十六进制的转换成十进制后用chr(数字)可以直接得到相应的中文字符(包括ASCII字符),但对于八位的GB18030码,举个例子如82328D35,我至今不知道是什么东东。还好,它不影响我们对中文字符的猜解,因为四位的十六进制GB18030码已经包含了足够多的汉字,至少到现在为止,我还没有遇到猜不出来的汉字。对于具体的转化过程,不就不在这儿罗嗦了,我把它放在附加文档中了,还包括了我已经转化好的正在使用中的对照表,Access格式的。
有了 Access格式的Unicode-GB18030-中文字符的对照表,我们现在就可以在自动注入程序中查询汉字Unicode编码所对应的汉字了。方法很简单,下面是我在自动注入的时候查询对照表的程序代码,注意我写注释的那几行。
Function Get_Field_Name(iUrl,Flen)
dim conn , i,rs,ch,SQL,result,char
result=""
set conn=GetConnection(server.MapPath("UnicodeMap.mdb"),"") ‘打开对照表数据连接
For i= 1 To Flen
ch=GetChar(Replace(iUrl,"[POS]",i),0,65535,0)
SQL="select chr from GB18030 where DU="&ch ‘查询注入时获取的unicode码的中文
set rs=get_rs(conn,SQL,1)
if rs.recordcount=1 then ‘找到对应的中文,包括ASCII
char=rs(0)
else
response.write “没有相应的字符”
resoponse.end
end if
result=result&char
rs.close
set rs=nothing
Next
conn.close ‘关闭数据连接
set conn=nothing
Get_Field_Name=result
end Function
补充一点,对于SQL Server中汉字的Unicode编码的获取,在我的SQL Server数据信息自动探测一文中已经介绍得非常清楚了。16次,也只有16次判断,我们就可以确定任何一个汉字的Unicode编码。
Access中汉字猜解
对于Access,其字符处理函数与SQL Server中不一样,见下表。
Access SQL Server 说明
asc(字符) unicode(字符) 返回某字符的编码
chr(数字) nchar(数字) 与asc相反,根据数字编码返回字符
mid(字符串,N,L)
substring(字符串,N,L)
返回字符串从N个字符起长度为L的子字符串,即N到N+L之间的字符串
在猜测汉字时,我们也可以用 GetFieldValue(iUrl,TableName,FieldName,PrimaryKey,PKValue,minlen,maxlen) 函数调用,不过有几点需要注意:
1.查询条件,由于字符处理函数与SQL Server中不同,修改为:
CheckFieldValue=" and 1=(select count(*) from [TABLE] where [IDN]=[ID] and asc(mid([FN],[POS],1))> [N])"
2.Asc码的取值范围。汉字通过ASC 函数运算后的取值范围,我没有试验过,不知道最小值是负的多少。所以这儿的取值范围下限指定多少就看你的了,只要包括你猜解的汉字就行了。不过范围适当大一点也没有关系,毕竟这儿的处理函数指数级缩小猜测范围,大不了多计算几次而已。
至于上限值,去零肯定不会有问题。如果有ASCII字符,取值上限指定为255就可以了,我想这对计算时间来说,几乎没有什么影响,至多猜一个字符多计算一次而已。为了通用性,还是取255吧。
3.GetFieldValue函数中得到ASC值后,直接用chr()函数转化成汉字或字符,不用再调用字符对照表。
我重看了这篇文章N遍,感觉Asscess中汉字猜测范围总有些不妥,毕竟时间就是生命,这儿多几次,那儿多几次,对于单个字符来说,可能不算什么,可如果猜测的数据量比较大后这就可能对程序执行效率造成很大的影响。经过我对chr函数的参数测试后,发现chr函数的参数有效范围是-32768- 65535,所以汉字的ASC码取值范围(-32768,0),经过16次猜测运算,便可以知道对应的ASC码,如果加上ASCII字符,则需要17次猜解运算。
本文对SQL自动注入中的汉字问题,提出了自己的一点看法和主张。如果有什么不妥的地方,希望大家批评指正。同时附上一个字符编码综合查询工具,可以在汉字-汉字Unicode编码-Asc码中互查。