|
深入浅析 |
|
|
深入浅析.NET应用程序SQL注入
这篇文章主要介绍了.NET应用程序SQL注入的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
1.准备工具:SQLSERVER,VisualStudio
2.数据库脚本和.net代码(c#)
3.SqlServerProfiler
SQL脚本代码:
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 USEMASTER
GO
--检索SQLTMP数据库是否存在
IFEXISTS(SELECTFROMSYSDATABASESWHEREname=''SQLTMP'')
--删除SQLTMP数据库
DROPDATABASESQLTMP
GO
--创建数据库
CREATEDATABASESQLTMP
GO
--使用SQLTMP数据库
USESQLTMP
GO
-------------创建一张表用来验证SQL注入漏洞----------------
--检索表是否存在
IFEXISTS(SELECTFROMSYSOBJECTSWHEREname=''admin'')
--删除表
DROPTABLEadmin
GO
--创建表
CREATETABLEadmin
(
idINTPRIMARYKEYIDENTITY(1,1),--设置主键
nameVARCHAR(20)NOTNULL,--用户名
passVARCHAR(20)NOTNULL--密码
)
-------------插入一条测试数据---------------------------
INSERTINTOadminVALUES(''admin'',''admin'')
--查询插入数据
SELECTFROMadmin 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
usingSystem.Data;
usingSystem.Data.SqlClient;
namespaceSQLTmp
{
classProgram
{
//数据库连接字符串
publicstaticStringstrCon="DataSource=.;InitialCatalog=SQLTMP;IntegratedSecurity=True";
//创建数据库连接对象
staticSqlConnectionSqlCon=newSqlConnection(strCon);
staticvoidMain(string[]args)
{
Console.WriteLine("请输入用户名:");
Stringname=Console.ReadLine();
Console.WriteLine("请输入密码:");
Stringpass=Console.ReadLine();
try
{
Programp=newProgram();
//打开数据库连接
p.Open();
stringsql="SELECTCOUNT()FROMadminWHEREname=''"+name+"''ANDpass=''"+pass+"''";
SqlCommandsqlcom=newSqlCommand(sql,SqlCon);
inti=(int)sqlcom.ExecuteScalar();
if(i>0)
{
Console.WriteLine("登录成功!");
}
else
{
Console.WriteLine("登录失败!");
}
Console.ReadLine();
}
catch(Exception)
{
throw;
}
finally{
//关闭数据库连接
pass.Clone();
}
}
//打开数据库连接
publicvoidOpen()
{
//关闭状态下打开数据库连接
if(SqlCon.State==ConnectionState.Closed)
{
SqlCon.Open();
}
//中断情况下打开数据库连接
if(SqlCon.State==ConnectionState.Broken)
{
//关闭
SqlCon.Close();
SqlCon.Open();
}
}
//关闭数据库连接
publicvoidClose(){
if(SqlCon.State==ConnectionState.Open||SqlCon.State==ConnectionState.Broken)
{
SqlCon.Close();
}
}
}
}
我们来测试一下
输入正确的账号密码:
adminadmin
登录成功
输入错误的账号密码:
testtest
登录失败
我们在用户名输入:''or1=1--
密码:123
会发现也能登录成功!
数据库中没有这个账号密码,还会登录成功?
why?
0x03剖析
我们来剖析一下SQL语句的运行过程
利用我的SQL语句跟踪工具(SQLServerProfiler)
单击链接
运行
我们来看一下输正确的账号密码SQL语句的样子
在我们的SQLServer中执行看看,有符合条件的数据
我们再来看看输入错误的账号密码SQL语句的样子
在我们的SQLServer中执行看看,没有符合条件的数据
我们再来看看最后一次的输入的账号密码的SQL语句的样子
我们来看看图片中的SQL语句我们的上面的SQL语句对比一下
1
2
3 SELECTCOUNT()FROMSQLTMPWHEREname=''admin''ANDpass=''admin''
SELECTCOUNT()FROMSQLTMPWHEREname=''''or1=1--''ANDpass=''123''
我们会发现我们输入的用户名变成了空,后面多了or1=1--''这又是为什么,什么原因导致的???
到离这里我们就应该看看这一段代码:
1
2 stringsql="SELECTCOUNT()FROMadminWHEREname=''"+name+"''ANDpass=''"+pass+"''";
我们可以看出SQL是中的name和pass是变量是用户输入的账号和密码
我们来看一下输入的用户名:''or1=1--
那么用户如输入''的时候就会自动把name=''''闭合
而or1=1将where条件永远成立
--在SQL是注释的意思会将后面的SQL语句注释掉!!!
那么我们就可以这么认为SQL语句到最后是这个样子的
1 SELECTCOUNT()FROMSQLTMPWHEREname=''''or1=1 0x04防御
有攻击的方式是会有防御的方式
据我所知常用的有俩种方式:
1.通过SQLParameter
好处:预编译SQL语句防止被转意
用法:
1
2
3
4
5
6
7
8
9
10
11 stringsql="SELECTCOUNT()FROMadminWHEREname=[url=home.php?mod=space&uid=116087]@name[/url]ANDpass=@pass";
//创建SParameter[]
SqlParameter[www.visa158.com]para={
www.hunanwang.net"@name",name),
newSqlParameter("@pass",pass)
};
SqlCommandsqlcom=newSqlCommand(sql,SqlCon);
//通过Parameters.addRange方法将para[]放进去
sqlcom.Parameters.AddRange(para);
inti=(int)sqlcom.ExecuteScalar();
2.存储过程
1.首先在数据库中创建存储过程
1
2
3
4
5 CREATEPROCLogin(@nameVARCHAR(20),@passVARCHAR(20))
AS
SELECTCOUNT()FROMadminWHEREname=@nameANDpass=@pass
GO
2.调用存储过程
1
2
3
4
5
6
7
8
9
10
11
12 SqlParameter[]para={
newSqlParameter("@name",name),
newSqlParameter("@pass",pass)
};
SqlCommandsqlcom=newSqlCommand();
sqlcom.Connection=SqlCon;
sqlcom.CommandText="Login";
//指定执行类型为存储过程
sqlcom.CommandType=CommandType.StoredProcedure;
sqlcom.Parameters.AddRange(para);
inti=(int)sqlcom.ExecuteScalar();
|
|
|
|
|
|
|
|
|
|
|