学习笔记-dotnet安全

admin 2023年1月30日01:20:15评论22 views字数 6390阅读21分18秒阅读模式

学习笔记-dotnet安全

dotnet安全



免责声明

本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.


案例

  • 越权漏洞反打钓鱼网站



反编译

反编译工具

  • dnSpy/dnSpy

    • dnSpyEx/dnSpy

  • icsharpcode/ILSpy



简介

ASP.NET 开发可以选用两种框架:ASP.NET Core 与 ASP.NET Framework

ASP.NET 开发也分为两种:

WebApplication

WEB 应用程序,改变代码后需要重启网页。具有 namespace 空间名称,项目中所有的程序代码文件,和独立的文件都被编译成为一个程序集,保存在 bin 文件夹中。

WebSite

WEB 网站,改变代码后不用重启网页。它没用到 namespace 空间名称,每个 asp 页面会转成一个 dll。


ASP.NET 的常见拓展名:

在 %windir%Microsoft.NETFrameworkv2.0.50727CONFIGweb.config 中有详细定义

  • aspx:应用程序根目录或子目录,包含 web 控件与其他

  • cs:类文件

  • aspx.cs:web 窗体后台程序代码文件

  • ascx:应用程序根目录或子目录, Web 用户控件文件。

  • asmx:应用程序根目录或子目录,该文件包含通过 SOAP 方式可用于其他 Web 应用程序的类和方法。

  • asax:应用程序根目录,通常是 Global.asax

  • config:应用程序根目录或子目录,通常是 web.config

  • ashx:应用程序根目录或子目录, 该文件包含实现 IHttpHandler 接口以处理所有传入请求的代码。

  • soap: 应用程序根目录或子目录。soap 拓展文件


常见文件

web.config

  1. web.config 是基于 XML 的文件,可以保存到 Web 应用程序中的任何目录中,这个文件包含了目录权限控制、数据库密码等等。

  2. 加载方式:当前目录搜索 -> 上一级到根目录 -> %windir%/Microsoft.NET/Framework/v2.0.50727/CONFIG/web.config -> %windir%/Microsoft.NET/Framework/v2.0.50727/CONFIG/machine.config -> 都不存在返回 null

Global.asax

  1. Global.asax 提供全局可用的代码,从 HttpApplication 基类派生的类,响应的是应用程序级别会话级别事件,通常 ASP.NET 的全局过滤代码就是在这里面。

App_Data

App_Data文件夹包含应用程序的本地数据存储

bin

包含应用程序所需的任何预生成的程序集

WEB 应用程序会把我们写的代码编译为 DLL 文件存放在 Bin 文件夹中,在 ASPX 中基本就是一些控件名,所以需要反编译他的 DLL 来进行审计。

例如 Logout.aspx


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Logout.aspx.cs" Inherits="Book.Logout" %>

在文件头中有这几个参数:

  • Language="C#" 表示脚本语言

  • AutoEventWireup="true" 表示是否自动关联某些特殊事件

  • CodeBehind="Logout.aspx.cs" 表示指定包含与页关联的类的已编译文件的名称

  • Inherits="Book.Logout" 表示定义供页继承的代码隐藏类

我们所关注的也就是 Inherits 的值,如上所示他指向了 Bin 目录下某个 dll 中 Book 类的 Logout 函数



dotnet代码审计


逻辑漏洞

ASP.NET 安全认证

在 web.config 中有四种验证模式

  • window - IIS 验证,在内联网环境中非常有用

  • Passport - 微软集中式身份验证,一次登录便可访问所有成员站点,需要收费

  • Form - 窗体验证,验证帐号 / 密码,Web 编程最佳最流行的验证方式

  • None - 表示 ASP.NET 自己根本不执行身份验证,完全依赖 IIS 身份验证

开启 form 窗体验证的同时还需要配置 web.config,不然就会出现问题,一般来说还需要配置最基本的页面访问权限, 比如禁止匿名用户访问。


<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>

当然还可以设置一些管理页面允许某某用户访问等等

除去web.config的配置通常还有两种写法来验证是否登陆。

第一种:在每个页面判断 Session["UserName"] 是否等于 null

第二种:类似 php 的 include 的继承,这也是本套程序使用的方法。

如果是没有任何验证的,也没有继承验证类的,无需登陆访问,这种就相当于是未授权了.

认证绕过示例

web.config


  <location path="purchase/orderdetail.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>

<authentication mode="Forms" />

这里定义了 purchase/orderdetail.aspx 可以匿名访问 ,其中 <authentication mode="Forms" /> 表示 Form 表单认证。

purchase/orderdetail.aspx


if (this.uid <= 0)
{
if (!(base.Request.QueryString["g"] == "p"))
{
base.Response.Redirect("../login.aspx");
return;
}
this.ph_pdf.Visible = false;
}

这里判断了参数 g

所以只需要访问 purchase/orderdetail.aspx?g=p 即可绕过跳转

认证绕过示例2






在 23-26 行判断 this.uid 的值来进行跳转,在 16 行定义了他的值,跟进 UserHelper.GetUserId


public static int GetUserId
{
get
{
if (Helper.IsUseAd && HttpContext.Current.Request.Cookies["userinfo"] == null)
{
UsersHelper.LoginAd(UserHelper.GetSamaccountName());
}
if (HttpContext.Current.Request.Cookies["userinfo"] != null)
{
return int.Parse(HttpContext.Current.Request.Cookies["userinfo"]["userid"]);
}
return -1;
}
}

this.uid 等于 cookies 中获取的 userinfo 的值,这一步可以伪造,30-33 这里他设置了管理员的布尔值,跟进 RoleHelper.IsAdmin


public static bool IsAdmin
{
get
{
string name = "IsAdmin";
string admin = RoleHelper.Admin;
bool? flag = HttpContext.Current.Session[name] as bool?;
if (flag == null)
{
flag = new bool?(UserHelper.IsInAnyRoles(admin));
HttpContext.Current.Session[name] = flag;
}
return flag.Value;
}
}

前面从 session 中获取,如果 flag 为 null 则从 UserHelper.IsInAnyRoles(admin) 获取。

跟进 IsInAnyRoles






可以看到只要我们传入的 cookies 中 roles 的等于传入的数组值就返回 true 其中 public static string Admin = "administrators";

所以构造 cookies: userinfo=userid=1&roles=administrators; 即可绕过认证



注入

辅助工具

  • SQL Server Profiler

漏洞示例1

login.aspx


public void LoginForm()
{
int num = UsersHelper.Login(this.txt_username.Text, this.txt_pwd.Text);
if (num > 0)
{
base.Response.Redirect(FormsAuthentication.GetRedirectUrl(num.ToString(), true));
}
else
{
Helper.Result(this, "用户名或者密码错误");
}
}

UsersHelper.Login


public static int Login(string username, string password)
{
string sql = " select uid from users_users where username=@username and password=@password; ";
SqlParameter[] prams = new SqlParameter[]
{
new SqlParameter("@username", username),
new SqlParameter("@password", Helper.Encrypt(password))
};
object obj = Instance.ExeScalar(sql, prams);
if (obj == null || obj == DBNull.Value)
{
return -1;
}
int num = int.Parse(obj.ToString());
if (num > 0)
{
UsersHelper.Login(num);
}
return num;
}

注意,这里看上去像是存在注入,但其实使用采用了参数化查询,通过 SqlParameter 传递参数

search.aspx






这里没有做处理,直接将参数与 text 拼接,然后传递给 ExeDataSet






ExeDataSet 中对参数进行了 checkSql 但无任何处理,所以没有过滤,参数将被直接带入查询

Payload: 1%' and 1=user--

漏洞示例2






看到 69-88 行,存在 SQL 查询, 但要触发执行命令需要 this.isview 为 true

在 30-36 行赋值只需要 t=view 即可

sid 没有经过任何过滤,同时 ExeDataSet 函数也不存在过滤,即存在注入。

Payload: purchase/orderdetail.aspx?g=p&t=view&sid=1%20and%201=user--



XSS

相关文章

  • Request Validation - Preventing Script Attacks

validateRequest

在 asp.net 中我们插入 XSS 代码经常会遇到一个错误 A potentially dangerous Request.Form






这是因为在 aspx 文件头一般会定义一句 <%@ Page validateRequest="true" %> ,当然也可以在 web.config 中定义,值得注意的是 validateRequest 的值默认为 true , 所以通常情况下 asp.net 基本上是不存在 XSS 的, 除非程序员把他的值改变。

比如


<pages validateRequest="false" controlRenderingCompatibilityVersion="3.5" enableEventValidation="false">
<controls>
<add tagPrefix="pg" namespace="SiteUtils" assembly="DNHelper" />
<add tagPrefix="pop" namespace="EeekSoft.Web" assembly="EeekSoft.Web.PopupWin" />
<add tagPrefix="dnc" namespace="Dotnetcms.Controls" assembly="DNHelper" />
<add tagPrefix="DayPilot" namespace="DayPilot.Web.Ui" assembly="DotnetControl" />
</controls>
</pages>


文件上传

分析案例


private void SaveFile()
{
string text = "../uploads/" + DateTime.Now.ToString("yyyy-MM") + "/";
string text2 = HttpContext.Current.Server.MapPath(text);
if (!Directory.Exists(text2))
{
Directory.CreateDirectory(text2);
}
HttpFileCollection files = HttpContext.Current.Request.Files;
string fileName = Path.GetFileName(files[0].FileName);
string extension = Path.GetExtension(files[0].FileName);
string text3 = Helper.ReadConfigValue(Helper.ReadConfigXml("~/app_data/allow_ext.xml"), "allow_ext").ToString().ToLower();
if (text3.Contains(extension.ToLower()))
{
string str = Guid.NewGuid().ToString() + extension;
string filename = text2 + str;
files[0].SaveAs(filename);
string s = string.Concat(new string[]
{
"{"jsonrpc" : "2.0", "result" :"",
HttpContext.Current.Server.HtmlEncode(fileName),
"", "id" : "",
HttpContext.Current.Server.HtmlEncode(text + str),
""}"
});
HttpContext.Current.Response.Write(s);
}
}

文件名由 uploads + DateTime.Now.ToString("yyyy-MM") + Guid.NewGuid().ToString() + extension 组成

格式类似 ../uploads/2019-10/30777b5a-bd82-48eb-9104-24afffd97243.png

所以能控制的只有 extension,他由 Path.GetExtension 直接获取文件后缀,但是 ReadConfigXml 读取 ~/app_data/allow_ext.xml 的文件做比较,比较典型的白名单所以这里不存在任意文件上传。

allow_ext.xml


<?xml version="1.0" standalone="yes"?>
<PItems>
<PItem Name="allow_ext" Value=".rar.zip.jpg.png.gif.doc.docx.xls.xlsx.ppt.pptx.jpeg.pdf" />
</PItems>


反序列化

相关工具

  • pwntester/ysoserial.net

其它学习教程。

学习笔记-dotnet安全学习笔记-dotnet安全



学习笔记-dotnet安全


原文始发于微信公众号(安全狗的自我修养):学习笔记-dotnet安全

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月30日01:20:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   学习笔记-dotnet安全https://cn-sec.com/archives/1390461.html

发表评论

匿名网友 填写信息