基于Ghidra和Neo4j的RPC剖析手艺 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

基于Ghidra和Neo4j的RPC剖析手艺

申博_新闻事件 申博 81次浏览 已收录 0个评论

关于我来讲,寻觅新型的横向渗入要领或风趣的代码实行手艺是一种消磨时光的好要领。由于Windows在启动时会天生大批的RPC效劳,所以,在寻觅异乎寻常的代码实行手艺的时候,难度会直线下落。一般来讲,这些运动的投入产出比照样异常客观的,由于SOC或EDR供应商每每专注于更罕见的已公之于众的手艺,而能够在主机上触发代码实行的新要领的问世能够会给观察团队的事变带来贫苦。

在之前的文章中,我试图找出能够用于夹杂罕见进击署名的差别要领。自从撰写探究Mimikatz和lsass内部机制的文章以来,我收到了许多关于怎样找到所展现的lsass DLL加载手艺以及怎样辨认其他手艺方面的信息的要求。所以,在这篇文章中,我将为读者引见一个事变流程,协助人人检察Windows RPC要领内部;同时,还会引见一些异常有用的要领,将寻觅感兴趣的向量的事变量降至最低。

须要说的是,这篇文章的目的读者是那些对Windows底层功用感兴趣,而且不满足于已宣布的0dayzz或横向渗入手艺的人。而本文的重点就是供应一些主意,愿望能协助这些读者找到相干的新手艺。

因而,我们起首要做的是明白要辨认的对象。就横向渗入手艺而言,我们的抱负目的应当如许一种效劳——能够经由过程RPC举行长途交互,或许能够经由过程LPC暴露当地的效劳,用于将代码导入处于运转状况的历程中。

就如今来讲,在搜刮RPC效劳时,我们能够借助于RpcView,这是为数不多的东西之一,旨在以充足的粒度来公然RPC效劳,以至天生可编译的IDL。虽然这个东西异常棒,但我的关注点在于它是怎样完成RPC罗列的。相识这一点今后,我们就能够为本身的逆向东西定制某些迥殊的功用。因而,在本文的第一部份中,这就是我们将要探究的内容……以及怎样完成RPC罗列。

一旦我们控制了从历程中提取RPC信息的要领,接下来要做的事变,就是相识公然的RPC要领是不是会触发我们感兴趣的API挪用,比方CreateProcess或LoadLibrary。这是我们将在本文的第二部份在要集合议论的主题。

自动罗列RPC

 关于RPC罗列,我最初是借助于Rpcrt4.dll(这是Windows供应的库,用于支撑RPC运转时)以及RpcView的源代码,来相识Windows RPC的内部运转机制的。

如今,我们要更进一步:相识RPC效劳器的相干信息。幸亏微软为我们供应了一个关于怎样建立RPC效劳器的优异文档,所以,这里将以它为基本,并进一步引见怎样暴露出单一要领。我已将相干项目添加到Github,以轻易人人参考。

假如我们考核该示例RPC项目的主函数,会发明有许多API是用于启动RPC效劳器的,包括:

RpcServerUseProtseqEp:用于设置端点以接收RPC衔接。

RpcServerRegisterIf:用于向RPC运转时注册RPC接口。

RpcServerListen:启动RPC效劳器的侦听功用。

 注重,统统这些API挪用都是从Rpcrt4.dll导出的,所以,让我们将其交给Ghidra,看看这些函数是怎样运作的。

 假如我们从RpcServerUseProtseqEp最先,我们会它会搜检RPC运转时是不是已加载到一个历程中:

基于Ghidra和Neo4j的RPC剖析手艺

这里会考证全局变量RpcHasBeenInitialized,假如它被设置为false,那末实行流程将进入PerformRpcInitialization。终究,这会触发InitializeRpcServer的一个函数,而该函数则会初始化GlobalRpcServer的全局变量:

 基于Ghidra和Neo4j的RPC剖析手艺

那末,GlobalRpcServer是干啥的?假如细致考核RpcView的代码,我们会在RpcInternals.h中找到答案:

typedef struct _RPC_SERVER_T{
  MUTEX_T                        Mutex;
  ULONG                          __bIslistening;
  ULONG                          bIsListening;
  ULONG                          MinimumCallThreads;
  ULONG                          Wait;
  ULONG                          OutCalls;
  ULONG                          Unk1;
  ULONG                          InCalls;
  ULONG                          Unk2;
  SIMPLE_DICT_T                  AddressDict;
  ULONG                          lAvailableCalls;
  ULONG                          Unk3;
  SIMPLE_DICT_T                  _ProtSeqQueue;
  ULONG                          Unk4[8];
  ULONG                          OutPackets;
  ULONG                          Unk5;
  MUTEX_T                        Mutex2;
  ULONG                          MaxCalls;
  ULONG                          Unk6;
  VOID PTR_T                     hEvent;
  ULONG                          Unk7[4];
  SIMPLE_DICT_T                  InterfaceDict;
  ULONG                          _bIsListening;
  ULONG                          bIsMaxCalls1234;
  ULONG                          Unk8[6];
  ULONG                          InPackets;
  ULONG                          Unk9;
  RPC_FORWARD_FUNCTION PTR_T     pRpcForwardFunction;
  ULONG                          Unk10[6];
  SIMPLE_DICT_T                  AuthenInfoDict;
  LIST_ENTRY_T                   RpcIfGroupListEntry;
  ULONG    PTR_T                 __SRWLock;
  LIST_ENTRY_T                   field_1E0;
}RPC_SERVER_T, PTR_T PRPC_SERVER_T;

 如上所示,这个对象供应了许多对我们的RPC逆向剖析异常有用的字段。个中,我们要迥殊关注一下InterfaceDict,它是SIMPLE_DICT_T的一个实例。再次回忆RpcView的代码,我们发明这个构造的花样为:

 typedef struct _SIMPLE_DICT_T{
    VOID PTR_T PTR_T    pArray;
    UINT                ArraySizeInBytes;
    UINT                NumberOfEntries;
    VOID PTR_T          SmallArray[SIMPLE_DICT_SMALL_ARRAY];
}SIMPLE_DICT_T, PTR_T PSIMPLE_DICT_T;

个中,pArray字段是一个指向RPC_INTERFACE_T的指针;RPC_INTERFACE_T具有以下规划:

typedef struct _RPC_INTERFACE_T
{
  PRPC_SERVER_T              pRpcServer;
  ULONG                      Flags;
  ULONG                      Unk1;
  MUTEX_T                    Mutex;
  ULONG                      EpMapperFlags;
  ULONG                      Unk2;
  RPC_MGR_EPV PTR_T          pMgrEpv;
  RPC_IF_CALLBACK_FN PTR_T   IfCallbackFn;
  RPC_SERVER_INTERFACE_T     RpcServerInterface;
  PMIDL_SYNTAX_INFO          pSyntaxInfo;
  VOID PTR_T                 pTransfertSyntaxes;
  ULONG                      TransfertSyntaxesCount;
  ULONG                      __Field_C4;
  ULONG                      NbTypeManager;
  ULONG                      MaxRpcSize;
  UUID_VECTOR  PTR_T         pUuidVector;
  SIMPLE_DICT_T              RpcInterfaceManagerDict;
  UCHAR                      Annotation[MAX_RPC_INTERFACE_ANNOTATION];
  ULONG                      IsCallSizeLimitReached;
  ULONG                      currentNullManagerCalls;
  ULONG                      __Field_150;
  ULONG                      __Field_154;
  ULONG                      __Field_158;
  ULONG                      SecurityCallbackInProgress;
  ULONG                      SecurityCacheEntry;
  ULONG                      field_164;
  VOID PTR_T                 __SecurityCacheEntries[16];
  SIMPLE_DICT_T              FwEpDict;
  ULONG                      Unk3[6];
  struct RPCP_INTERFACE_GROUP PTR_T pRpcpInterfaceGroup;
}RPC_INTERFACE_T, PTR_T PRPC_INTERFACE_T;

这里,我们又找到一个RpcServerInterface字段。实际上,该字段是由我们在POC中建立的MIDL来举行添补的(详细拜见useless_s.c):

static const RPC_SERVER_INTERFACE useless___RpcServerInterface =
    {
    sizeof(RPC_SERVER_INTERFACE),
    {{0xaaf3c26e,0x2970,0x42db,{0x91,0x89,0xf2,0xbc,0x0e,0x07,0x3e,0x7c}},{1,0}},
    {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}},
    (RPC_DISPATCH_TABLE*)&useless_v1_0_DispatchTable,
    0,
    0,
    0,
    &useless_ServerInfo,
    0x04000000
};

依据RpcView对该构造的定义,我们发明个中含有以下所示的规划:

typedef struct _RPC_SERVER_INTERFACE_T{
    UINT                     Length;
    RPC_IF_ID                InterfaceId;
    RPC_IF_ID                TransferSyntax;
    PRPC_DISPATCH_TABLE_T    DispatchTable;
    UINT                     RpcProtseqEndpointCount;
    PRPC_PROTSEQ_ENDPOINT_T  RpcProtseqEndpoint;
    RPC_MGR_EPV PTR_T        DefaultManagerEpv;
    void const PTR_T         InterpreterInfo;
    UINT                     Flags ;
} RPC_SERVER_INTERFACE_T, PTR_T PRPC_SERVER_INTERFACE_T;

一样,这里也有许多字段,同时,我们对MIDL天生的代码很感兴趣,比方在我们的MIDL编译中天生的DispatchTable:

static const RPC_DISPATCH_TABLE useless_v1_0_DispatchTable =
    {
    2,
    (RPC_DISPATCH_FUNCTION*)useless_table
    };

这里的值2实际上是暴露的要领的数目,这一点我们能够从RPC_DISPATCH_TABLE构造的定义中看出来:

typedef struct _RPC_DISPATCH_TABLE_T{
    UINT                            DispatchTableCount;
    RPC_DISPATCH_FUNCTION  PTR_T    DispatchTable;
    ULONG_PTR_T                     Reserved;
} RPC_DISPATCH_TABLE_T, PTR_T PRPC_DISPATCH_TABLE_T;

与之前的RpcServerInterface字段相干的另一个字段是InterpreterInfo,该字段在我们的示例项目中添补了以下值:

static const MIDL_SERVER_INFO useless_ServerInfo =
    {
    &useless_StubDesc,
    useless_ServerRoutineTable,
    useless__MIDL_ProcFormatString.Format,
    useless_FormatStringOffsetTable,
    0,
    0,
    0,
    0};

该构造的定义以下所示:

typedef struct  _MIDL_SERVER_INFO_T {
    PMIDL_STUB_DESC_T                pStubDesc;
    const VOID PTR_T PTR_T           DispatchTable;
    const unsigned char PTR_T        ProcString;
    const unsigned short PTR_T       FmtStringOffset;
    const VOID PTR_T PTR_T           ThunkTable;
    RPC_IF_ID PTR_T                  pTransferSyntax;
    ULONG_PTR_T                      nCount;
    VOID PTR_T                       pSyntaxInfo;
} MIDL_SERVER_INFO_T, PTR_T PMIDL_SERVER_INFO_T;

这个构造在其DispatchTable字段中包括一个函数指针数组,能够用来检索经由过程RPC接口公然的统统要领,其定义以下所示:

static const SERVER_ROUTINE useless_ServerRoutineTable[] =
    {
    (SERVER_ROUTINE)UselessProc,
    (SERVER_ROUTINE)Shutdown
    };

关于上述内存构造,我们必需细致加以考核(我们能够借助于RpcView来辨认它们的内存规划,并时候坚持内存处于最新状况)。为此,我们须要在内存中先找到GlobalRpcServer,由于它是其他构造的基础之地点。

借助于Ghidra,我们能够看到这个全局变量位于内存的.data部份:

为了在内存中找到该指针,能够应用RpcView遍历.data部份,每次考核8个字节(在x64 arch的情况下),而且搜检构造中的潜伏字段,就好像它是指向RPC_SERVER的准确指针一样。假如统统字段都找到了,RpcView就以为它有一个指向RPC_SERVER的有用指针;不然,直接转至接下来的8个字节。

我们将在本身的东西中运用雷同的战略来定位雷同的指针:

在目的历程内存中定位Rpcrt4.dll模块。

定位DLL的.data节。

基于Golang的加密货币挖矿恶意软件攻击活动

Golang也称Go,是一种开源的编程语言。Trend Micro研究人员在分析6月的一起攻击活动时发现该语言被用于传播加密货币挖矿机。该攻击活动中使用的传播器可以扫描运行着有漏洞软件的机器来进行传播。该攻击活动的攻击链如下: 图1. 攻击感染链 技术细节 基于Golang的传播器 恶意软件会寻找多个攻击入口来将恶意软件传播到其他的系统中。在该攻击活动中,攻击者使用了常用的SSH服务和多个其他漏洞利用。攻击活动使用了基于Golang的传播器来扫描: · SSH · Misconfigured Redis server · ThinkPHP exploit · Drupal exploit · Atlassian Confluence server (CVE-2019-3396) 图2是扫描Redis端口的传播器代

每次读取8个字节,并消除作为潜伏的RPC_SERVER指针的援用。

搜检InterfaceDict等字段以确保这些字段与期望值互相婚配,比方NumberOfEntries是不是为一个合理的值。

 假如完全性搜检失利,继承处置惩罚背面的8个字节。

完全的代码能够从这里找到。

假如统统顺利,我们就会找到响应的RPC_SERVER实例,为此,我们只需遍历所需的struct字段以辨认每一个公然的要领。

按理说,我们能够在此告一段落了,但有时候为潜伏的要领地点设置RPC要领称号也是异常有用的。要在绑缚的Microsoft二进制文件中公然要领称号,我们能够从Microsoft的标记效劳器中猎取PDB。为此,我们能够运用Dbghelp库,如许,我们就能够以编程体式格局下载每一个PDB,并在运转时剖析每一个要领称号。详细代码,能够从这里下载。

那末,假如我们将统统零部件拼集到一同的话,将会发作什么情况呢? 我们天然愿望能够它能够报告从当前运转的统统历程中导出的统统RPC要领:

基于Ghidra和Neo4j的RPC剖析手艺

如今,统统看起来都运转一般,但假如我们将已辨认的RPC要领和地点导出到JSON文件中的话,那末这会在进一步自动化过程当中发挥更大的作用。为此,我们能够借助于niohmann的JSON C ++库来轻松完成这一点。

读者能够在此处找到RpcEnum的完全项目源代码。如今,这些代码适用于Windows 10 1903体系上的x64二进制文件,愿望对人人构建本身的东西能够有所协助。

应用Ghidra举行Headless剖析

由于如今已能够罗列和提取历程中的RPC要领称号和地点,我们接下来须要一种要领来剖析每一个要领,以协助辨认后续挪用。如今手动实行该操纵须要消费相当多的时候,但荣幸的是,Ghidra已公然了一个headless剖析器,它运转运用扩大剧本,所以无需翻开UI或与UI举行交互。

如今,我们已能够预先晓得将运用哪一个DLL和EXE,因而,接下来须要对其举行逐一剖析,并将它们添加到Ghidra的项目中,以便今后编写剧本。为此,我们能够运用以下敕令,并将每一个模块作为参数举行通报:

.\support\analyzeHeadless.bat C:\Ghidra Windows.gpr -import C:\windows\system32\target.dll

一旦完成上述敕令(固然,这一定须要一段时候),我们将取得一个Ghidra项目,个中含有与待剖析的EXE和DLL相干RPC要领:

基于Ghidra和Neo4j的RPC剖析手艺

建立好包括我们感兴趣的模块的项目后,我们接下来须要找到一种有用的要领来探究统统这些数据。我发明一种迥殊有用的要领,即为每一个公然的RPC要领建立挪用图,以协助明白所做的外部Win32 API挪用。为此,能够借助一个简朴的Python剧原本剖析我们之前天生的JSON文件,并在运用每一个模块的自定义Jython post-script来挪用headless型Ghidra实例。读者能够从这里下载这个python剧本。

我们的Ghidra Jython post-script将应用Ghidra公然的API来递归剖析RPC要领,并为每一个要领映照一个挪用图。读者能够在此处找到实行该操纵的简朴示例。一旦实行,我们就能够建立一个由内部函数和Win32函数构成的CSV文件,这些函数将被各个公然的RPC要领所挪用:

 基于Ghidra和Neo4j的RPC剖析手艺

上面的CSV文件包括了我们搜刮潜伏有用的代码途径所需的统统信息,接下来让我们更进一步——尝试建立一个挪用图,以便以交互体式格局举行探究。

Neo4j,不仅可用于Bloodhound

我猜本文的大多数读者都是由于Bloodhound而打仗Neo4j的。尽人皆知,Bloodhound为使Infosec社区相识图论的有用性做了许多事变,然则这类手艺的用处远不止在AD收集上搜刮DA这么有限。 

在最先探究Neo4j的壮大功用之前,我们起首须要晓得怎样将数据转换为所需的图表面。实际上,Neo4J许可用户直接从CSV文件导入数据。为此,我们起首须要运用以下体式格局建立节点:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:/log-int.csv" AS csv
FIELDTERMINATOR ' '
MERGE (f:IntFunction {name:csv.name, module:csv.module }); 
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:/log-ext.csv" AS csv
FIELDTERMINATOR ' '
MERGE (f:ExtFunction {name:csv.name, module:csv.module });
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:/log-rpc.csv" AS csv
FIELDTERMINATOR ' '
MERGE (f:RPCFunction {name:csv.name, module:csv.module });

接下来,我们须要在每一个节点之间建立响应的关联(或边)。个中,这里最显著的关联就是“挪用”关联,我们将在个中标记后续函数是怎样挪用每一个函数的。为此,我们能够运用以下挪用:

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:/log-int.csv" AS csv
FIELDTERMINATOR ' '
MATCH (f {name:csv.calledby, module:csv.calledbymodule })
MATCH (f2 {name:csv.name, module:csv.module})
MERGE (f)-[:Calls]->(f2)
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM "file:/log-ext.csv" AS csv
FIELDTERMINATOR ' '
MATCH (f {name:csv.calledby, module:csv.calledbymodule })
MATCH (f2 {name:csv.name, module:csv.module})
MERGE (f)-[:Calls]->(f2)
USING PERIODIC COMMIT 500
LOAD CSV WITH HEADERS FROM "file:/log-rpc.csv" AS csv
FIELDTERMINATOR ' '
MATCH (f {name:csv.calledby, module:csv.calledbymodule })
MATCH (f2 {name:csv.name, module:csv.module})
MERGE (f)-[:Calls]->(f2)

加载后,我们应当发明本身如今能够运用挪用图,并能够在数据库中举行搜刮,以下面的NetrJobEnum RPC要领所示:

基于Ghidra和Neo4j的RPC剖析手艺

借助于一个包括我们能够交互式探究的关联的数据库,辨认能够感兴趣的代码途径会变得越发轻易。比方,假如我们想要找出终究将挪用Win32 API(如LoadLibraryExW)且少于3跳的统统RPC要领,我们能够运用Cypher查询:

MATCH p=(:RPCFunction)-[:Calls*3]->(:ExtFunction {name: "LoadLibraryExW"}) RETURN p

 基于Ghidra和Neo4j的RPC剖析手艺

怎样举行响应的修正,使其能够辨认不仅挪用LoadLibraryExW,还挪用注册表API(如RegQueryValueExW)的代码途径呢?详细以下所示:

 基于Ghidra和Neo4j的RPC剖析手艺

上面的例子不仅表明当Neo4j与准确的数据集结应时到底有何等壮大,同时,也展现了为取得感兴趣的代码途径而拼集一个东西链是何等简朴。

小结

关于某些读者来讲,能够已发明了能够借助于Neo4j阅读节点的种种范畴。

第一个范畴是Control Flow Guard,虽然在Ghidra的9.0.4中处置惩罚得很好,但它依然将挪用图显现为一个节点,并在尝试递归标识挪用的函数时中断代码途径。如今来看,这似乎是从VTABLE挪用的假造要领而至,由于Ghidra如今还没法很好地剖析这些要领,因而,致使涌现熟习的__guard_dispatch_icall函数。

第二个范畴是初始加载速率。虽然运用Neo4J探究挪用能够进步剖析阶段的速率(最少对我来讲是如许),但如今须要斟酌将数据加载到数据库所需的时候。我对Neo4J的相识并不多,因而能够有一些要领能够进步将数据加载到数据库以及查找关联的机能。

这些范畴将是我下一步的研讨重点,由于我继承探究RPC和LPC的潜伏进击面,但假如你有任何革新要领的发起,请随时与我联络。

本文翻译自:https://blog.xpnsec.com/analysing-rpc-with-ghidra-neo4j/


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明基于Ghidra和Neo4j的RPC剖析手艺
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址