基于rpc调用-动态加载ssp

此篇文章结合学到的知识做个总结

微软有个api为AddSecurityPackage,可以添加ssp,这里就看下其的实现逻辑,这里从将从公开这个 API 的 secur32.dll 这个 DLL 文件开始,主要为本人进行了修改以及自己去复现的总结

在 Ghidra 打开这个 DLL 文件,这实际上只是一个调用 sspcli.dll 的包装器
在这里插入图片描述
我们这边主要是看sspicli.dll的实现逻辑是调用了NdrClientCall3
函数,注意这个函数就是我们接下来要调用rpc调用进行模拟的需要的函数

在这里插入图片描述
在调用 NdrClientCall3 时,我们发现传递了以下参数:
在这里插入图片描述
这里给出了一个值是3 的 nProcNum 参数,如果我们深入研究 sspirpc_ProxyInfo 结构体,就会发现 RPC 接口的 UUID 为 4f32adc8-6052-4a04-8701-293ccf2096f0:
在这里插入图片描述
下面就是18001e2c0指向的是18001e2c0
在这里插入图片描述
在这里插入图片描述
然后我们再看是哪个函数对这个接口做了调用,看到一个很可疑的程序
在这里插入图片描述
下面可以看到我们将Proc3_SspirCallrpc的接口的参数给拿出来了
在这里插入图片描述
想要知道函数调用的参数,那么其实就是需要去动态调试了,这里就不一一叙说,此处借鉴网图
在这里插入图片描述
接下来我们来看下xpn老师的rpc源码

前期主要是根据上面的那张图去构造rpc的packet,然后下面主要就是去绑定rpc,然后模拟AddSecurityPackage函数的调用

#define SECURITY_WIN32
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <Windows.h>
#include <subauth.h>
#include <sspi.h>
#include <Dbghelp.h>
#include "sspi_h.h"

int main(int argc, char **argv) {
	RPC_STATUS status;
	UNICODE_STRING packageName;
	UWORD packetLen = 0;
	unsigned char* pszStringBinding = NULL;
	unsigned long ulCode;
	unsigned long long unk1;
	unsigned char rpcPacket[0x2000];
	long out1 = 0, out2 = 0;
	void* out3 = (void*)0;
	struct Struct_144_t out4;

	printf("\nAddSecurityPackage Raw RPC Example... by @_xpn_\n\n");

	if (argc != 2) {
		printf("Usage: %s PACKAGE_PATH\n");
		return 1;
	}

	printf("[*] Building RPC packet\n");

	// Init RPC packet
	memset(&packageName, 0, sizeof(packageName));
	memset(rpcPacket, 0, sizeof(rpcPacket));

	// Build DLL to be loaded by lsass
	packageName.Length = strlen(argv[1]) * 2;
	packageName.MaximumLength = (strlen(argv[1]) * 2) + 2;
	mbstowcs((wchar_t*)(rpcPacket + 0xd8), argv[1], (sizeof(rpcPacket) - 0xd8) / 2);
	packetLen = 0xd8 + packageName.MaximumLength;

	// Complete RPC packet fields
	*(unsigned long long*)rpcPacket = 0xc4; // ??
	*(unsigned short*)(rpcPacket + 2) = packetLen; // Length of packet
	*(unsigned long long*)((char*)rpcPacket + 8) = GetCurrentProcessId();  // Process ID
	*(unsigned long long*)((char*)rpcPacket + 16) = GetCurrentThreadId();  //Thread ID
	*(unsigned long long*)((char*)rpcPacket + 0x28) = 0x0b;  // RPC call ID
	*(void**)((char*)rpcPacket + 0xd0) = &unk1; // ??

	// Copy package name into RPC packet
	memcpy(rpcPacket + 0x40, &packageName, 8);
	*(unsigned long long*)((char*)rpcPacket + 0x48) = 0xd8;  // Offset to unicode ssp name

	// Create the RPC connection string
	//主要为绑定rpc通道
	status = RpcStringBindingCompose(NULL,
		(unsigned char*)"ncalrpc",
		NULL,
		(unsigned char*)"lsasspirpc",
		NULL,
		&pszStringBinding);
	if (status) {
		return 1;
	}
	
	// Create RPC handle
	printf("[*] Connecting to lsasspirpc RPC service\n");
	//该 RpcBindingFromStringBinding函数从绑定句柄的字符串表示返回绑定句柄
	status = RpcBindingFromStringBinding(pszStringBinding, &default_IfHandle);
	if (status) {
		return 1;
	}

	memset(&out4, 0, sizeof(out4));

	RpcTryExcept
	{
		// Create our RPC context handle
		printf("[*] Sending SspirConnectRpc call\n");
		long ret = Proc0_SspirConnectRpc((unsigned char *)NULL, 2, &out1, &out2, &out3);

	    // Make the "AddSecurityPackage" call directly via RPC
		printf("[*] Sending SspirCallRpc call\n");
		//此处函数就是对NdrClientCall3函数的封装
		ret = Proc3_SspirCallRpc(out3, packetLen, rpcPacket, &out2, (unsigned char **)&out3, &out4);
	}
	RpcExcept(1)
	{
		ulCode = RpcExceptionCode();
		if (ulCode == 0x6c6) {
			printf("[*] Error code 0x6c6 returned, which is expected if DLL load returns FALSE\n");
		}
		else {
			printf("[!] Error code %x received\n", ulCode);
		}
	}
	RpcEndExcept

	return 0;
}
//下面的函数是为了满足链接需要而写的,没有的话会出现链接错误
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
	return(malloc(len));
}

void __RPC_USER midl_user_free(void __RPC_FAR* ptr)
{
	free(ptr);
}

如下图所示就是在构造rpc的包
在这里插入图片描述

为了找出SSPI RPC服务器在LSASS过程中使用的具体端点,我们可以对sspisrv.dll进行反向工程。在导出的函数SspiSrvInitialize()中,我们看到如下调用:
RpcServerUseProtseqEpW(L"ncalrpc", 0xAu, L"lsasspirpc", 0);
所述 RpcServerUseProtseqEp函数告诉RPC运行时库使用具有指定端点组合指定的协议序列,用于接收远程过程调用
Protseq
指向要在RPC运行时库中注册的协议序列的字符串标识符的指针。
MaxCalls
ncacn_ip_tcp协议序列的积压队列长度。所有其他协议序列将忽略此参数。使用RPC_C_PROTSEQ_MAX_REQS_DEFAULT指定默认值。请参阅备注。
Endpoint
指向用于为Protseq参数中指定的协议序列创建绑定的端点地址信息的指针。
SecurityDescriptor
指向为安全子系统提供的可选参数的指针。仅用于ncacn_np和ncalrpc协议序列。所有其他协议序列将忽略此参数。不建议在端点上使用安全描述符以使服务器安全。此参数未出现在此API的DCE规范中

sspisrv.dll的导出函数SspiSrvInitialize如下所示,可以看到下面调用了RpcServerUseProtseqEpW,RpcServerUseProtseqEp函数告诉RPC运行时库使用具有指定端点组合指定的协议序列,用于接收远程过程调用
,下面就可以看到lsasspirpcSSPI RPC服务器在LSASS过程中使用的具体端点就是lsasspirpc,所以上面源码中调用RpcStringBindingCompose使用的就是lsasspirpc,sspisrv.dll是LSA SSPI RPC interface DLL

在这里插入图片描述
然后我们可以查看Proc0_SspirConnectRpc和Proc3_SspirCallRpc就是对NdrClientCall3函数的封装

long Proc0_SspirConnectRpc( 
    /* [string][unique][in] */ unsigned char *arg_1,
    /* [in] */ long arg_2,
    /* [out] */ long *arg_3,
    /* [out] */ long *arg_4,
    /* [context_handle][out] */ void **arg_5)
{

    CLIENT_CALL_RETURN _RetVal;

    _RetVal = NdrClientCall3(
                  ( PMIDL_STUBLESS_PROXY_INFO  )&DefaultIfName_ProxyInfo,
                  0,
                  0,
                  arg_1,
                  arg_2,
                  arg_3,
                  arg_4,
                  arg_5);
    return ( long  )_RetVal.Simple;
    
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里再来看下DefaultIfName_ProxyInfo结构体,该结构包含有关远程接口描述的信息

static const MIDL_STUBLESS_PROXY_INFO DefaultIfName_ProxyInfo =
    {
    &DefaultIfName_StubDesc,
    sspi__MIDL_ProcFormatString.Format,
    DefaultIfName_FormatStringOffsetTable,
    (RPC_SYNTAX_IDENTIFIER*)&_RpcTransferSyntax,
    2,
    (MIDL_SYNTAX_INFO*)DefaultIfName_SyntaxInfo
    
    };

其实就是不断的包含,最后我们定位到下面的位置,第一个就是我们上面找到的的uuid的接口
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Safenet SSP是一种安全软件平台,旨在保护数据和信息的安全性。它提供了一套全面的工具和功能,以帮助企业保护其敏感数据和应用程序免受未经授权的访问和攻击。 Safenet SSP的主要功能包括身份认证、访问控制、数据加密和密钥管理。身份认证是通过验证用户的身份来确保只有授权人员能够访问敏感信息和应用程序。访问控制允许企业根据用户的权限和角色来限制其能够访问的资源和功能。数据加密是一种保护数据安全的重要手段,Safenet SSP提供了高级的加密算法和安全存储设备,可确保数据在传输和存储过程中得到充分保护。密钥管理是一种管理加密密钥的方法,它确保密钥在生成、存储、传输和销毁过程中得到适当的保护和控制。 通过使用Safenet SSP,企业可以确保其敏感数据和应用程序受到强大且可靠的安全保护。它提供了一套综合的解决方案,能够满足不同组织的安全需求。无论是在云环境中还是在本地服务器上,Safenet SSP都能提供高度可靠的安全性,帮助企业防御潜在的威胁和攻击。 总之,Safenet SSP是一种功能强大的安全软件平台,通过提供全面的安全工具和功能,帮助企业保护敏感数据和应用程序的安全性。它的身份认证、访问控制、数据加密和密钥管理等功能,使得企业能够有效地应对安全威胁和风险。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值