Your printer is not your printer ! – Hacking Printers at Pwn2Own Part I

IoT 7个月前 admin
124 0 0

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

印表機近年來已成為企業內網中不可或缺的設備之一,功能也隨著科技的發展日益增多,除了一般的傳真及列印之外,也開始支援 AirPrint 等雲端列印服務,讓列印更加方便,直接使用行動裝置就可以輕鬆列印,更成為了 IoT 中,不可或缺的一環,正因為其便利,也常被用於列印公司內部機敏文件,使得在企業中印表機的安全性更加的重要。
打印机近年来已成为企业内网中不可或缺的设备之一,功能也随着科技的发展日益增多,除了一般的传真及打印之外,也开始支持 AirPrint 等云端打印服务,让打印更加方便,直接使用移动设备就可以轻松打印,更成为了 IoT 中,不可或缺的一环,正因为其便利,也常被用于打印公司内部机敏文件,使得在企业中打印机的安全性更加的重要。

而前年我們也在 Canon 及 HP 的印表機中發現了 Pre-auth RCE 的漏洞(CVE-2022-24673 及 CVE-2022-3942) 及 Lexmark 發現漏洞(CVE-2021-44734),並在 Pwn2Own Austin 2021 中取得了 Canon ImageCLASS MF644Cdw、 HP Color LaserJet Pro MFP M283fdw 及 Lexmark MC3224i 的控制權,而成功獲得 Pwn2Own 中駭客大師(Master of Pwn) 的點數,這篇研究將講述 Canon 及 HP 漏洞的細節及我們的利用方式。
而前年我们也在 Canon 及 HP 的打印机中发现了 Pre-auth RCE 的漏洞( CVE-2022-24673 及 CVE-2022-3942) 及 Lexmark 发现漏洞( CVE-2021-44734),并在 Pwn2Own Austin 2021 中取得了 Canon ImageCLASS MF644Cdw、 HP Color LaserJet Pro MFP M283fdw 及 Lexmark MC3224i 的控制权,而成功获得 Pwn2Own 中黑客大师(Master of Pwn) 的点数,这篇研究将讲述 Canon 及 HP 漏洞的细节及我们的利用方式。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

此份研究亦發表於 HITCON 2022 及 CODE BLUE 2022,你可以從這裡取得投影片!
此份研究亦发表于 HITCON 2022 及 CODE BLUE 2022,你可以从 这里取得投影片!

Printer

早期在使用印表機時,往往會需要使用 IEEE1284 或是 USB 的 Printer cable 來將印表機接上電腦,並且在使用時會額外裝上廠商所附的驅動程式。而現今的印表機已可以接上網路,並多了各式各樣的功能,通常只要將印表機接上區網,區網中的電腦就可以輕易地發現你所新安裝的印表機。
早期在使用打印机时,往往会需要使用IEEE1284或是USB的Printer cable来将打印机接上电脑,并且在使用时会额外装上厂商所附的驱动程序。 而现今的打印机已可以接上网络,并多了各式各样的功能,通常只要将打印机接上区网,区网中的电脑就可以轻易地发现你所新安装的打印机。

目前市面上的印表機預設都開了非常多的服務,不外乎就是為了讓列印更加方便,像是 FTP、AirPrint、Bonjour 等等服務。
目前市面上的打印机默认都开了非常多的服务,不外乎就是为了让打印更加方便,像是 FTP、AirPrint、Bonjour 等等服务。

Motivation

為何要研究印表機呢? 为何要研究打印机呢?

紅隊內網需求 红队内网需求

過去我們團隊在執行紅隊演練過程中,印表機普遍出現於現代企業內網中,幾乎都會有一台以上,但往往是被忽略的一塊,也常常沒在更新。印表機本身也非常適合作為攻擊者的藏身處,通常很難被偵測出來。值得一提的是比較大型的企業也很有可能將其接上 AD,成為獲取機密資訊的入口。
过去我们团队在执行红队演练过程中,打印机普遍出现于现代企业内网中,几乎都会有一台以上,但往往是被忽略的一块,也常常没在更新。 打印机本身也非常适合作为攻击者的藏身处,通常很难被侦测出来。 值得一提的是比较大型的企业也很有可能将其接上AD,成为获取机密信息的入口。

Pwn2Own Austin 2021

另外一點是印表機在 2021 時,首次成為了 Pwn2Own Mobile 主要推動的目標之一,而我們剛好當時也準備再次挑戰 Pwn2Own 舞台,便決定一探究竟。
另外一点是打印机在 2021 时,首次成为了 Pwn2Own Mobile 主要推动的目标之一,而我们刚好当时也准备再次挑战 Pwn2Own 舞台,便决定一探究竟。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

起初我們原本以為非常簡單,跟多數的 IoT 設備一樣,能輕易的找到 Command injection 問題,殊不知有不少印表機都是使用 RTOS,並非一般的 Linux 系統,但這更是驅動了我們挑戰它的決心。
起初我们原本以为非常简单,跟多数的 IoT 设备一样,能轻易的找到 Command injection 问题,殊不知有不少打印机都是使用 RTOS,并非一般的 Linux 系统,但这更是驱动了我们挑战它的决心。

本篇將會著重在較為精彩的 Canon 及 HP 部分,Lexmark 有機會再談談。
本篇将会着重在较为精彩的 Canon 及 HP 部分,Lexmark 有机会再谈谈。

Analysis

剛開始研究的時候,我們參考了許多資料都是需要拆解硬體來分析,才能獲得 debug console,再用 dump memory 方式來獲取原始的 firmware。但最終我們採用了其他的方式,並沒有拆解任何一台印表機。
刚开始研究的时候,我们参考了许多资料都是需要拆解硬件来分析,才能获得 debug console,再用 dump memory 方式来获取原始的 firmware。 但最终我们采用了其他的方式,并没有拆解任何一台打印机。

Canon

Firmware Extract 固件提取

初始分析版本為 v6.03,我們一開始使用 binwalk 去解析它,但 firmware 是經過混淆的,我們並沒辦法直接解開。
初始分析版本为 v6.03,我们一开始使用 binwalk 去解析它,但 firmware 是经过混淆的,我们并没办法直接解开。

圖: 經過混淆的 Canon ImageCLASS MF644Cdw fimware
圖: 經過混淆的 Canon ImageCLASS MF644Cdw fimware
Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

我們這邊也嘗試過了 TREASURE CHEST PARTY QUEST: FROM DOOM TO EXPLOIT by Synacktiv 及 Hacking Canon Pixma Printers – Doomed Encryption by Contextis Research 的研究,但這次是完全不同的系列,我們無法使用同樣的方法解開混淆過的 firmware。
我们这边也尝试过了TREASURE CHEST PARTY QUEST: FROM DOOM TO EXPLOIT by Synacktiv及Hacking Canon Pixma Printers – Doomed Encryption by Contextis Research的研究,但这次是完全不同的系列,我们无法使用同样的方法解开混淆过的 firmware。

於是我們開始分析混淆過的 firmware 格式及內容。
于是我们开始分析混淆过的 firmware 格式及内容。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

我們大致上可以從混淆過的 firmware 看到,每個混淆過的 firmware 的開頭都會是 NCFW 這個 Magic,並帶有該 firmware 大小,而其他部分則是混淆過的資料。
我们大致上可以从混淆过的 firmware 看到,每个混淆过的 firmware 的开头都会是 NCFW 这个 Magic,并带有该 firmware 大小,而其他部分则是混淆过的资料。

於是我們開始猜想,也許這台印表機舊版本的 firmware 沒有混淆,直到某一版才開始混淆,如果可以抓到中介版本,可能有機會獲得解混淆的方法。而這個 Magic 也可以讓我們辨別是不是經過混淆的。
于是我们开始猜想,也许这台打印机旧版本的 firmware 没有混淆,直到某一版才开始混淆,如果可以抓到中介版本,可能有机会获得解混淆的方法。 而这个 Magic 也可以让我们辨别是不是经过混淆的。

以下這個網址是透過官網或是擷取封包獲得的 firmware 下載網址
以下这个网址是通过官网或是撷取封包获得的 firmware 下载网址

https://pdisp01.c-wss.com/gdl/WWUFORedirectTarget.do?id=MDQwMDAwNDc1MjA1&cmp=Z01&lang=EN

經過分析後,可以拆分為多個部分 经过分析后,可以拆分为多个部分

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

約略可以歸納出下載網址的規則,我們可以藉由這個方法來載到所有版本的 firmware,當時我們載到的版本有
约略可以归纳出下载网址的规则,我们可以藉由这个方法来载到所有版本的 firmware,当时我们载到的版本有

  • V2.01
  • V4.02
  • V6.03
  • V9.03
  • V10.02

而 v10.02 是幾周後會釋出的版本,可以先從這邊優先載到。載完所有版本後,我們發現該系列版本的 firmware 都是經過混淆的,無法從先前版本獲得解混淆的方法。但我們可以下載 Canon 其他系列的印表機,嘗試找找是否有類似的混淆演算法。載完約有 130 GB 大小。透過 grep 找 NCFW 及 servicemode.html 可以找到未混淆的 firmware。
而 v10.02 是几周后会释出的版本,可以先从这边优先载到。 载完所有版本后,我们发现该系列版本的 firmware 都是经过混淆的,无法从先前版本获得解混淆的方法。 但我们可以下载 Canon 其他系列的打印机,尝试找找是否有类似的混淆算法。 载完约有 130 GB 大小。 透过grep找 NCFW 及 servicemode.html 可以找到未混淆的firmware。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

最後找到四組符合條件的 firmware,我們這邊選擇了 WG7000 系列的印表機來分析,並找到了疑似解混淆的函式。
最后找到四组符合条件的 firmware,我们这边选择了 WG7000 系列的打印机来分析,并找到了疑似解混淆的函式。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

很幸運的,藉由重寫這個函式,可以解出明文的 MF644Cdw firmware。
很幸运的,藉由重写这个函式,可以解出明文的 MF644Cdw firmware。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

在解出 firmware 之後,必須找出 firmware 的 image base address,IDA 才能有效地辨別跟 reference。此處可透過常見的分析工具 rbasefind 來找 image base。
在解出 firmware 之后,必须找出 firmware 的 image base address,IDA 才能有效地辨别跟 reference。 此处可通过常见的分析工具 rbasefind 来找 image base。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

一開始找出的 base 為 0x40b0000,但丟進 IDA 後,卻發現大部分的函式與 debug message 的字串對映不起來。
一开始找出的 base 为 0x40b0000,但丢进 IDA 后,却发现大部分的 函式 与 debug message 的字符串对映不起来。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

如上圖所示,loc_4489AC08 應該指向函式名稱的字串,然而此地址卻不是正常的字串,而是被當成 code 區段,內容也不是字串,表示此位置並非真正位置,而是有些許的偏移,但正常 function 的解析沒甚麼太大問題。這邊可以先找一個已知函式名稱的函式和找到屬於他的函式名稱字串來做調整,找到其中差異的 offset 後,將 image base 調到正確位置就可以了。最終找到的 image base 為 0x40affde0。調整完後,可看到原本的函式已可正確識別函式名稱。
如上图所示, loc_4489AC08 应该指向函式名称的字符串,然而此地址却不是正常的字符串,而是被当成 code 区段,内容也不是字符串,表示此位置并非真正位置,而是有些许的偏移,但正常 function 的解析没什么太大问题。 这边可以先找一个 已知函式名稱的函式 和找到属于他的 函式名稱字串 来做调整,找到其中差异的 offset 后,将 image base 调到正确位置就可以了。 最终找到的 image base 为 0x40affde0。 调整完后,可看到原本的函数已可正确识别函数名称。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

接下來就可以正常分析 firmware,而初步分析後可得知,Canon ImageCLASS MF644Cdw 架構如下
接下来就可以正常分析 firmware,而初步分析后可得知,Canon ImageCLASS MF644Cdw 架构如下

  • OS – DryOSV2
    • Customized RTOS by Canon
  • ARMv7 32bit little-endian
  • Linked with application code into single image
    • Kernel
    • Service

HP

HP 的 firmware 取得相對容易許多,我們可以透過 binwalk -Z 來獲得正確的 firmware,約略需要花 3-4 天左右的時間,而其他找 image base address 等步驟,則與 Canon 相同,此處就不贅述。經過初步分析後,HP Color LaserJet Pro MFP M283fdw 架構如下
HP 的 firmware 取得相对容易许多,我们可以透过 binwalk -Z 来获得正确的 firmware,约略需要花 3-4 天左右的时间,而其他找 image base address 等步骤,则与 Canon 相同,此处就不赘述。 经过初步分析后,HP Color LaserJet Pro MFP M283fdw 架构如下

  • OS
    • RTOS – Modify from ThreadX/Green Hills
  • ARM11 Mixed-endian
    • Code – little-endian
    • Data – Big-endian

Attack Surface

在現今市面上大多數的多功能事務機中,預設都會開啟一堆服務
在现今市面上大多数的多功能事务机中,默认都会开启一堆服务

Service Port Description
RUI TCP 80/443 Web interface
PDL TCP 9100 Page Description Language
PJL TCP 9100 Printer Job Language
IPP TCP 631 Internet Printing Protocol
LPD TCP 515 Line Printer Daemon Protocol
SNMP UDP 161 Simple Network Management Protocol
SLP TCP 427 Service Location Protocol
mDNS UDP 5353 Multicast DNS
LLMNR UDP 5355 Link-Local Multicast Name Resolution

一般來說,為了方便管理,通常都會開 RUI (web 介面) ,再來是 9100 Port 也是印表機常使用的 Port,主要會用來傳輸列印的資料。其他部分則會依照廠商不同而有所不同,不過上述所列的服務通常都會有,且預設大部分都是開啟的。在評估過這些服務後,決定注重在發現服務及 DNS 系列的協定,因為我們的長期經驗下來,常常觀察到 vendor 在開發這些服務時,往往是自行開發實作,而不是使用存在已久的 Open Source。但實際上來說,實作這些協定很容易出現問題的。我們當時主要分析的服務主要有 SLPmDNS 及 LLMNR
一般来说,为了方便管理,通常都会开 RUI (web 接口) ,再来是 9100 Port 也是打印机常使用的 Port,主要会用来传输打印的数据。 其他部分则会依照厂商不同而有所不同,不过上述所列的服务通常都会有,且预设大部分都是开启的。 在评估过这些服务后,决定注重在发现服务及DNS系列的协议,因为我们的长期经验下来,常常观察到vendor在开发这些服务时,往往是自行开发实作,而不是使用存在已久的Open Source。 但实际上来说,实作这些协议很容易出现问题的。 我们当时主要分析的服务主要有SLP、mDNS及LLMNR。

接下來就以 Pwn2Own Austin 2021 作為 Case Study,來看看這些協定常會有哪些問題。
接下来就以 Pwn2Own Austin 2021 作为 Case Study,来看看这些协议常会有哪些问题。

Hacking printers at Pwn2Own

Canon

Service Location Protocol

SLP 是一種服務發現協定,主要用於讓電腦快速找到印表機,過去在 ESXI 中,SLP 也常常出問題,而在 Canon 的 SLP 服務,主要由 Canon 自己實作,SLP 服務細節可參考 RFC2608。在我們分析 SLP 前必須先了解 SLP 封包大致上的結構
SLP 是一种服务发现协议,主要用于让电脑快速找到打印机,过去在 ESXI 中, SLP 也常常出问题,而在 Canon 的 SLP 服务,主要由 Canon 自己实作,SLP 服务细节可参考 RFC2608。 在我们分析SLP前必须先了解SLP封包大致上的结构

圖: SLP Packet Structure Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

這邊只需要關注function-id,此欄位會決定請求型態,也會決定 payload 部分的格式。而 Canon 只有實作 Service Request 及 Attribute Request 兩種。
这边只需要关注 function-id ,此字段会决定请求型态,也会决定 payload 部分的格式。 而 Canon 只有实作 Service Request 及 Attribute Request 两种。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

在 Attribute Request (AttrRqst) 的請求中,允許使用者可以根據 service 及 scope 來獲得 attribute list。 scope 可以定義要找的範圍,如 canon 印表機。
在 Attribute Request (AttrRqst) 的请求中,允许用户可以根据 service 及 scope 来获得 attribute list。 scope 可以定义要找的范围,如 canon 打印机。

Example: Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而 Attribute request 結構大致如下
而 Attribute request 结构大致如下

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

主要是長度(Length)及數值(Value)的組合,通常在 Parse 這種格式,很容易出問題,需要特別注意,而實際上 Canon 在 Parse 這個結構時就出了問題。
主要是长度(Length)及数值(Value)的组合,通常在 Parse 这种格式,很容易出问题,需要特别注意,而实际上 Canon 在 Parse 这个结构时就出了问题。

Vulnerability

Canon 在 parse scope list 時,會將跳脫字元轉換成 ASCII,例如 \41 會轉換成 A ,然而這個簡單轉換會有怎樣的問題呢? 我們來看一下 Pseudo code
Canon 在 parse scope list 时,会将跳脱字符转换成 ASCII,例如 \41 会转换成 A ,然而这个简单转换会有怎样的问题呢? 我们来看一下 Pseudo code

int parse_scope_list(...){
    char destbuf[36];
    unsigned int max = 34;
    parse_escape_char(...,destbuf,max);
}

如上面程式碼所示,在 parse_scope_list 中,會先分配 36 bytes 的 destbuf 並且指定最大大小 34 到 parse_escape_char 中,這邊沒甚麼問題,讓我們來看一下 parse_escape_char
如上面代码所示,在 parse_scope_list 中,会先分配 36 bytes 的 destbuf 并且指定最大大小 34 到 parse_escape_char 中,这边没什么问题,让我们来看一下 parse_escape_char

int __fastcall parse_escape_char(unsigned __int8 **pdata, _WORD *pdatalen, unsigned __int8 *destbuf, _WORD *max)
{
  unsigned int idx; // r7
  int v7; // r9
  int v8; // r8
  int error; // r11
  unsigned __int8 *v10; // r5
  unsigned int i; // r6
  int v12; // r1
  int v13; // r0
  unsigned int v14; // r1
  bool v15; // cc
  int v16; // r2
  bool v17; // cc
  unsigned __int8 v18; // r0
  int v19; // r0
  unsigned __int8 v20; // r0
  unsigned int v21; // r0
  unsigned int v22; // r0

  idx = 0;
  v7 = 0;
  v8 = 0;
  error = 0;
  v10 = *pdata;
  for ( i = (unsigned __int16)*pdatalen; i && !v7; i = (unsigned __int16)(i - 1) )
  {
    v12 = *v10;
    if ( v12 == ',' )
    {
      if ( i < 2 )
        return -4;
      v7 = 1;
    }
    else
    {
      if ( v12 == '\\' ) //----------------------[1]
      {
        if ( i < 3 )
          return -4;
        v13 = v10[1];
        v14 = v13 - '0';
        v15 = v13 - (unsigned int)'0' > 9;
        if ( v13 - (unsigned int)'0' > 9 )
          v15 = v13 - (unsigned int)'A' > 5;
        if ( v15 && v13 - (unsigned int)'a' > 5 )
          return -4;
        v16 = v10[2];
        v17 = v16 - (unsigned int)'0' > 9;
        if ( v16 - (unsigned int)'0' > 9 )
          v17 = v16 - (unsigned int)'A' > 5;
        if ( v17 && v16 - (unsigned int)'a' > 5 )
          return -4;
        if ( v14 <= 9 )
          v18 = 0x10 * v14;
        else
          v18 = v13 - 0x37;
        if ( v14 > 9 )
          v18 *= 0x10;
        *destbuf = v18; //-------------------[2]
        v19 = v10[2];
        v10 += 2;
        v20 = (unsigned int)(v19 - 0x30) > 9 ? (v19 - 55) & 0xF | *destbuf : *destbuf | (v19 - 0x30) & 0xF;
        *destbuf = v20;
        LOWORD(i) = i - 2;
        if ( !strchr((int)"(),\\!<=>~;*+", *destbuf) )
        {
          v21 = *destbuf;
          if ( v21 > 0x1F && v21 != 0x7F )
            return -4;
        }
        goto LABEL_40;
      }
      if ( strchr((int)"(),\\!<=>~;*+", v12) ) //-----------------------[3]
        return -4;
      v22 = *v10;
      if ( v22 <= 0x1F || v22 == 0x7F )
        return -4;
      if ( v22 != ' ' )
      {
        v8 = 0;
        goto LABEL_35;
      }
      if ( !v8 )
      {
        v8 = 1;
LABEL_35:
        if ( (unsigned __int16)*max <= idx ) //----------------------[4] 
        {
          error = 1;
          goto next_one;
        }
        if ( v8 )
          LOBYTE(v22) = 32;
        *destbuf = v22;
LABEL_40:
        ++destbuf;
        idx = (unsigned __int16)(idx + 1);
      }
    }
next_one:
    ++v10;
  }
  if ( error )
  {
    *max = 0;
    debugprintff(3645, 4, "Scope longer than buffer provided");
LABEL_48:
    *pdata = v10;
    *pdatalen = i;
    return 0;
  }
  if ( idx )
  {
    *max = idx;
    goto LABEL_48;
  }
  return -4;
}

可以看到 [3] 針對是沒有跳脫字元的處理,會在 [4] 檢查是否有超過最大長度,然而在有跳脫字元的處理中 [1] ,並沒有任何對長度的檢查,直接將轉換後的結果放到 destination buffer 中 [2],一旦給定的字串多數為跳脫字元的情況,就會造成 stack overflow。
可以看到 [3] 针对是没有跳脱字元的处理,会在 [4] 检查是否有超过最大长度,然而在有跳脱字元的处理中 [1] ,并没有任何对长度的检查,直接将转换后的结果放到 destination buffer 中 [2] ,一旦给定的字串多数为跳脱字符的情况,就会造成 stack overflow。

在找到漏洞之後,第一件事就是先看看本身有甚麼保護,方便後續的利用。但分析了一下發現,Canon 印表機本身並沒有任何記憶體相關的保護。
在找到漏洞之后,第一件事就是先看看本身有什么保护,方便后续的利用。 但分析了一下发现,Canon 打印机本身并没有任何内存相关的保护。

Protection

  • No Stack Guard
  • No DEP
  • No ASLR

沒有 Stack Guard、沒有 DEP 也沒有 ASLR,可以說是 hacker friendly ! 如同回到 90 年代,一個 stack overflow 就可以打天下。接下來就如同過往的 Binary Exploitation 利用手法,找個地方放 shellcode 再覆蓋 return address 跳到 shellcode 就會有任意程式碼執行了! 最終我們找到了 BJNP 這個服務來放我們的 shellcode。
没有 Stack Guard、没有 DEP 也没有 ASLR,可以说是 hacker friendly ! 如同回到 90 年代,一个 stack overflow 就可以打天下。 接下来就如同过往的 Binary Exploitation 利用手法,找个地方放 shellcode 再覆盖 return address 跳到 shellcode 就会有任意代码执行了! 最终我们找到了 BJNP 这个服务来放我们的 shellcode。

BJNP

BJNP 本身也是個服務發現協定,由 Canon 自己所設計,過去也曾經有許多漏洞,Synacktiv 也曾經利用該協定漏洞來獲得印表機控制權,這邊不多做細節上的介紹,更多細節可參考這篇,我們也用了類似的手法。 BJNP 本身會將可控的 session 資料放在已知的 global buffer 中,我們可用這個功能來將我們的 shellcode 放到一個固定的位置上,基本上也沒甚麼限制。
BJNP 本身也是个服务发现协议,由 Canon 自己所设计,过去也曾经有许多漏洞, Synacktiv 也曾经利用该协议漏洞来获得打印机控制权,这边不多做细节上的介绍,更多细节可参考 这篇,我们也用了类似的手法。 BJNP 本身会将可控的 session 资料放在已知的 global buffer 中,我们可用这个功能来将我们的 shellcode 放到一个固定的位置上,基本上也没什么限制。

我們重新整理一下利用步驟 我们重新整理一下利用步骤

Exploitation Step

  • 使用 BJNP 將我們的 shellcode 放到固定的已知位置。
    使用BJNP将我们的shellcode放到固定的已知位置。
  • 觸發 SLP 的 stack overflow 並覆蓋 return address
  • 跳到我們的 shellcode 上執行程式碼。 跳到我们的 shellcode 上执行代码。

Pwn2Own Austin 2021

通常 Pwn2Own 中會需要你證明已打下印表機,這邊可以自由選擇呈現方式,我們起初想要的是如同我們 exploit Lexmark 印表機一樣,直接將 logo 放到印表機的 LCD 螢幕上。
通常 Pwn2Own 中会需要你证明已打下打印机,这边可以自由选择呈现方式,我们起初想要的是如同我们 exploit Lexmark 打印机一样,直接将 logo 放到打印机的 LCD 屏幕上。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

但在比賽前,我們花了很多時間在研究該怎麼把 logo 印到螢幕上,花在這邊時間可能比找洞跟寫 exploit 時間還要長,最後也因為時間上的因素,採取了比較保險的做法,直接改掉 Service Mode 字串,再印到螢幕上。
但在比赛前,我们花了很多时间在研究该怎么把 logo 印到屏幕上,花在这边时间可能比找洞跟写 exploit 时间还要长,最后也因为时间上的因素,采取了比较保险的做法,直接改掉 Service Mode 字符串,再印到屏幕上。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

不過實際上印圖片到螢幕上並不難,其他隊伍有找到方法,有興趣的人可以嘗試看看。
不过实际上印图片到屏幕上并不难,其他队伍有找到方法,有兴趣的人可以尝试看看。

Debug

看到這邊可能會有人想問這種環境如何 debug,實際上來說要 debug 通常有幾種方法:
看到这边可能会有人想问这种环境如何 debug,实际上来说要 debug 通常有几种方法:

  • 接上硬體獲得 debug console 後,用裡面的功能來 debug
    接上硬件获得 debug console 后,用里面的功能来 debug
  • 用舊的洞獲得程式碼執行後,裝上客製的 debugger
    用旧的洞获得代码执行后,装上客制的 debugger

不過我們當時已更新到最新,該版本不存在舊的漏洞,需要降版本回去,而拆解硬體同樣也須額外的時間,但當時我們已經有漏洞了,時間上來說不太合成本。最後我們還是採用最傳統的 sleep debug 法去 debug。
不过我们当时已更新到最新,该版本不存在旧的漏洞,需要降版本回去,而拆解硬件同样也须额外的时间,但当时我们已经有漏洞了,时间上来说不太合成本。 最后我们还是采用最传统的sleep debug法去debug。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

在 ROP 或執行 shellcode 後,將結果印到網頁或其他可見的地方,然後呼叫 sleep 後,就可從網頁或其他讀出結果,最後再重開機,接下來就是不斷重複此流程。不過實際上更好的做法還是接上 debug console 會方便一點。
在 ROP 或执行 shellcode 后,将结果印到网页或其他可见的地方,然后呼叫 sleep 后,就可从网页或其他读出结果,最后再重开机,接下来就是不断重复此流程。 不过实际上更好的做法还是接上 debug console 会方便一点。

接下來講講 HP 印表機 接下来讲讲 HP 打印机

HP

LLMNR 是與 mDNS 非常相似的一個協定,提供了區網中的域名解析功能,但比 mDNS 更單純一點,通常也會配合一些服務發現協定。這邊簡單介紹此機制:
LLMNR 是与 mDNS 非常相似的一个协议,提供了区网中的域名解析功能,但比 mDNS 更单纯一点,通常也会配合一些服务发现协议。 这边简单介绍此机制:

在區網域名解析時,Client A 會先用 multicast 方式,尋找區網中 Client C 位置
在区域名解析时,Client A 会先用 multicast 方式,寻找区网中 Client C 位置
Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

在 Client C 接收到之後,則會回傳給 Client A,簡單實現了區網域名的解析 Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而基本上 LLMNR 大多建立在 DNS 封包格式 上,格式如下:

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

主要會是 header 加上 Queries 這種格式,Count 表示不同型態的 query 數。
主要会是header加上Queries这种格式,Count表示不同型态的 query 数。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而每個 DNS Query 都是由許多 label 組成,每個 label 都會像上圖中這樣,都是長度加上字串的組合,也有 Message Compression 機制,過去在處理這些地方時,非常容易出現問題,在 BlackHat 2021 的 THE COST OF COMPLEXITY:Different Vulnerabilities While Implementing the Same RFC 中,也提到了類似的問題。
而每个DNS Query都是由许多 label 组成,每个 label 都会像上图中这样,都是长度加上字符串的组合,也有 Message Compression 机制,过去在处理这些地方时,非常容易出现问题,在 BlackHat 2021 的 THE COST OF COMPLEXITY:Different Vulnerabilities While Implementing the Same RFC 中,也提到了类似的问题。

Vulnerability

我們回頭來看一下 HP 的實作: 我们回头来看一下 HP 的实作:

int llmnr_process_query(...){
    char result[292];
    consume_labels(llmnr_packet->qname,result,...);
    ...
}

這邊可以看到 HP 在處理 LLMNR 封包時,會將一個固定 buffer 傳入,用來放處理後的結果,而 consume_lables 則是主要用來處理 dns labels。
这边可以看到 HP 在处理 LLMNR 封包时,会将一个固定 buffer 传入,用来放处理后的结果,而 consume_lables 则是主要用来处理 dns labels。

int __fastcall consume_labels(char *src, char *dst, llmnr_hdr *a3)
{
  int v3; // r5
  int v4; // r12
  unsigned int len; // r3
  int v6; // r4
  char v7; // r6
  bool v8; // cc
  int v9; // r0
  unsigned __int8 chr; // r6
  int result; // r0

  v3 = 0;
  v4 = 0;
  len = 0;
  v6 = 0;
  while ( 1 )
  {
    chr = src[v3]; //-------------[1]
    if ( !chr )
      break;
    if ( (int)len <= 0 )
    {
      v8 = chr <= 0xC0u;
      if ( chr == 0xC0 )
      {
        v9 = src[v3 + 1];
        v6 = 1;
        v3 = 0;
        src = (char *)a3 + v9;
      }
      else
      {
        len = src[v3++];
        v8 = v4 <= 0;
      }
      if ( !v8 )
        dst[v4++] = '.';
    }
    else
    {
      v7 = src[v3++];
      len = (char)(len - 1);
      dst[v4++] = v7; //----------[2]
    }
  }
  result = v3 + 1;
  dst[v4] = 0;
  if ( v6 )
    return 2;
  return result;
}

而在 consume_labels 中的 [1] 會先取得 label 長度,接著根據型態去處理,而在[2] 則是處理一般長度的情況,此處並沒有對長度做檢查,就直接將 label 寫進 dst buffer 中,導致了 stack overflow,到此處我們原以為差不多結束了,接下來應該如同 Canon 類似的方法就可以 Exploit 了。然而當我們在寫 Exploit 時發現 HP 比 Canon 多了一些保護機制。
而在 consume_labels 中的 [1] 会先获取 label 长度,接着根据类型处理, 而在 [2] 则是处理一般长度的情况,此处并没有对长度做检查,就直接将 label 写进 dst buffer 中,导致了 stack overflow,到此处我们原以为差不多结束了,接下来应该如同 Canon 类似的方法就可以 Exploit 了。 然而当我们在写 Exploit 时发现 HP 比 Canon 多了一些保护机制。

Protection 保护

  • No Stack Guard
  • XN(DEP)
  • Memory Protect Unit (MPU)
  • No ASLR

在 HP 印表機中,多了 XN 及 MPU 的記憶體保護措施,另外這個漏洞也有了更多的限制。我們只能 overflow 約 0x100 bytes 及不能有 null 字元,這大幅限制了我們的 ROP,使得我們沒辦法單靠 ROP 做到後續行動,需要另外找其他的漏洞或其他方法才能達成我們的目標。在一段時間後,我們開始思考,HP 印表機是如何去實作 XN(DEP) 及 MPU 的? 我們回顧一下 HP RTOS:
在HP打印机中,多了XN及MPU的内存保护措施,另外这个漏洞也有了更多的限制。 我们只能 overflow 约 0x100 bytes 及不能有 null 字符,这大幅限制了我们的 ROP,使得我们没办法单靠 ROP 做到后续行动,需要另外找其他的漏洞或其他方法才能达成我们的目标。 在一段时间后,我们开始思考,HP 打印机是如何去实践 XN(DEP) 及 MPU 的? 我们回顾一下 HP RTOS:

  • 所有 Service code 及 Kernel Code 都在同一個 Binary 中。
    所有 Service code 及 Kernel Code 都在同一个 Binary 中。
  • 大多數的 task 都跑在同一個記憶體空間底下(沒有 Process isolation),也幾乎都跑在高權限模式
    大多数的 task 都跑在同一个内存空间底下(没有 Process isolation),也几乎都跑在高权限模式

看完以上兩點,會想到是不是理解 HP RTOS 中的 MMU 及 MPU 就可以繞過呢?
看完以上两点,会想到是不是理解 HP RTOS 中的 MMU 及 MPU 就可以绕过呢?

我們來看一下 HP RTOS MMU 機制
我们来看一下 HP RTOS MMU 机制

MMU in HP M283fdw

在 HP M283fdw 中使用的是一階層的 Translation table 來做 Address translation ,每個 translation table entry 都表示 1MB 的 Section,而 Translation table 則是固定在 0x4003c000 這個位置上
在 HP M283fdw 中使用的是一阶层的 Translation table 来做 Address translation ,每个 translation table entry 都表示 1MB 的 Section,而 Translation table 则是固定在 0x4003c000 这个位置上

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而每個 translation table entry 都會對應到 physical address 及該 section 的權限,CPU 就是根據這些內容決定執行權限、記憶體內容修改權限,如果我們可以修改 translation table entry 的內容就可以更改記憶體權限,也可以透過它來 Mapping 任意 Physical address,這邊跟權限有關的主要會有 AP APX 跟 XN。
而每个 translation table entry 都会对应到 physical address 及该 section 的权限,CPU 就是根据这些内容决定执行权限、内存内容修改权限,如果我们可以修改 translation table entry 的内容就可以更改内存权限,也可以透过它来 Mapping 任意 Physical address, 这边跟权限有关的主要会有AP APX跟XN。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

我們可以從前述的漏洞中注意到,在有 stack overflow 且也跑在高權限下,就可通過 ROP 修改 translation table entry,但當我們對嘗試直接對 translation table 做寫入後,結果

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

造成印表機 Crash,查了一下發現是 memory fault exception,主要造成原因就是因為 Memory Protect Unit (MPU) 有對該記憶體區段做保護。

好,那我們就來看看 MPU 的機制。

MPU in HP M283fdw

MPU 主要功能是把 memory 拆分成好幾個 region 並定義每個 region 的權限,與 MMU 是完全不同的機制,很常出現在 IoT 設備中。 HP 則是在開機就會啟用,並將每個 region 定義好權限,因此無法自己操作 page table。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

在長時間逆向及參考 ARM Manual 之後,我們發現事實上只要清空 MPU_CTRL 就可關閉 MPU,在經過逆向後 HP M283fdw 的 MPU_CTRL 位置是在 0xE0400304,這邊稍微跟 ARM 的 spec 有點不同,不太確定原因就是了。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

Exploitation

在了解 HP 的 MMU 及 MPU 機制後,我們可輕易地利用 ROP 來關閉 MPU,並成功修改 translation table entry,我們可以任意的修改任何 serivce 的程式碼,這邊我們最後選擇了 Line Printer Daemon(LPD) 這個服務來修改,將它修改成後門: 讀入更多的 Payload 到指定的位置上,最終執行我們送過去的 shellcode。
在了解 HP 的 MMU 及 MPU 机制后,我们可轻易地利用 ROP 来关闭 MPU,并成功修改 translation table entry,我们可以任意的修改任何 serivce 的代码,这边我们最后选择了 Line Printer Daemon(LPD) 这个服务来修改,将它修改成后门: 读入更多的 Payload 到指定的位置上,最终执行我们送过去的 shellcode。

但有一點必須特別注意,覆蓋完 translation table entry 跟 LPD 的 code 後,務必要 flush TLB 跟清掉 I-cache 和 D-cache 不然很有可能還是跑在舊有的程式碼上面導致 exploit 失敗。
但有一点必须特别注意,覆盖完 translation table entry 跟 LPD 的 code 后,务必要 flush TLB 跟清掉 I-cache 和 D-cache 不然很有可能还是跑在旧有的代码上面导致 exploit 失败。

Flash TLB

flush_tlb:
    mov r12, #0
    mcr p15, 0, r12, c8, c7, 0

Invalidate I-cache

disable_icache:
    mrc p15, 0, r1, c1, c0, 0
    bic r1, r1, #(1 << 12)
    mcr p15, 0, r1, c1, c0, 0

我們重新整理了一下利用步驟 我们重新整理了一下利用步骤

Exploitation Step

  • 首先先觸發 LLMNR 的 stack overflow
    首先先触发 LLMNR 的 stack overflow
  • 利用有限的 ROP 關閉 MPU
    利用有限的ROP关闭MPU
  • 利用 ROP 改掉 translation table entry 獲得讀寫執行權限
    利用 ROP 改掉 translation table entry 获得读写执行权限
  • Flush TLB
  • 改掉 LPD service 的程式碼
    改掉 LPD service 的代码
  • 清掉 I-cache 和 D-cache
  • 使用改過的 LPD 讀我們的 shellcode 後並執行
    使用改过的 LPD 读我们的 shellcode 后并执行

Pwn2Own Austin 2021

到可以執行 shellcode 時,我們只剩一週時間,我們最後選擇跟 Canon 一樣使用改字串顯示 Pwned by DEVCORE 到 LCD 上。
到可以执行 shellcode 时,我们只剩一周时间,我们最后选择跟 Canon 一样使用改字符串显示 Pwned by DEVCORE 到 LCD 上。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而幸運的是,我們第一次嘗試就成功了:) 而幸运的是,我们第一次尝试就成功了:)

在這之後我們也嘗試了直接把後門改成 debug console 上面,方便利用許多功能,例如查看記憶體資訊,播放音樂等等功能,F-Secure Labs 在比賽時就使用播放音樂這個功能來呈現,非常有趣,可以到這裡看當時的情況。
在这之后我们也尝试了直接把后门改成 debug console 上面,方便利用许多功能,例如查看内存信息,播放音乐等等功能, F-Secure Labs 在比赛时就使用播放音乐这个功能来呈现,非常有趣,可以到 这里看当时的情况。

Result

在 Pwn2Own Austin 2021 中,我們打下其他設備跟印表機後最終獲得了第二名,以這次來說獲得不錯經驗,也學到了一些新東西。
在 Pwn2Own Austin 2021 中,我们打下其他设备跟打印机后最终获得了第二名,以这次来说获得不错经验,也学到了一些新东西。

Your printer is not your printer ! - Hacking Printers at Pwn2Own Part I

而對於一般用戶們,有什麼方法可以避免印表機被當作攻擊目標甚至是跳板呢?
而对于一般用户们,有什么方法可以避免打印机被当作攻击目标甚至是跳板呢?

Mitigation

Update

首先就是定期更新,上述的印表機都已有 patch,這邊是很常被大家忽略的一部分,我們很常看到印表機好幾年了都沒更新,甚至直接預設密碼放著,很容易就被當成目標。
首先就是定期更新,上述的打印机都已有 patch,这边是很常被大家忽略的一部分,我们很常看到打印机好几年了都没更新,甚至直接预设密码放着,很容易就被当成目标。

Disable unused service 禁用未使用的服务

另外一點就是盡可能關掉沒在用的服務, 大部分的印表機預設開啟過多平常根本不會用的服務,我們甚至認為可以關掉 discovery 服務,只要開你要用的就好了。
另外一点就是尽可能关掉没在用的服务, 大部分的打印机默认开启过多平常根本不会用的服务,我们甚至认为可以关掉 discovery 服务,只要开你要用的就好了。

Firewall

更好的做法可以再加上 firewall,大部分印表機也都有提供相關功能。
更好的做法可以再加上 firewall,大部分打印机也都有提供相关功能。

Summary

事實上,我們獲得 shellcode 執行後,除了印東西在 LCD 外,我們可以藉由印表機來竊取機密資訊,不論是機密文件或是一些 credential,印表機也是個平行移動 (Lateral Movement) 的點,而且很難被偵測到,是紅隊中非常好的目標。另外很多印表機上的發現服務系列的協定或是 DNS 系列的協定很常出問題,如果想找類似印表機或其他 IoT 設備的漏洞,也許可以優先朝這個方向看看。
事实上,我们获得shellcode执行后,除了印东西在LCD外,我们可以藉由打印机来窃取机密信息,不论是机密文件或是一些credential,打印机也是个平行移动(Lateral Movement)的点,而且很难被侦测到,是红队中非常好的目标。 另外很多打印机上的发现服务系列的协议或是 DNS 系列的协议很常出问题,如果想找类似打印机或其他 IoT 设备的漏洞,也许可以优先朝这个方向看看。

To be continue 待续

最後,我們在去年 Pwn2Own Toronto 2022 中,也在印表機系列中找到幾個漏洞,我們也將會在近期發佈詳細資訊,敬請期待 Part II
最后,我们在去年 Pwn2Own Toronto 2022 中,也在打印机系列中找到几个漏洞,我们也将会在近期发布详细信息,敬请期待 Part II

Reference 参考

原文始发于AngelboyYour printer is not your printer ! – Hacking Printers at Pwn2Own Part I

版权声明:admin 发表于 2023年10月10日 上午10:32。
转载请注明:Your printer is not your printer ! – Hacking Printers at Pwn2Own Part I | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...