施耐德NOE77101後門漏洞分析

韌體下載地址:

GitHub – ameng929/NOE77101_Firmware

文件目錄結構,這裡只列出了一些主要的文件資訊:

├── bin
├── ftp
├── fw
├── rdt
├── webloader.ini
└── wwwroot
    ├── SchneiderTFE.zip
    ├── cgi-bin
    ├── classes
    ├── conf
    │   ├── Gcnftcop.sys
    │   ├── bootp
    │   ├── dhcp
    │   ├── diag
    │   │   └── chkdsk.out
    │   ├── exec
    │   │   ├── NOE77101.bin
    │   │   └── kerVer
    │   ...
    ├── html
    │   ├── config.js
    │   	...
    ├── rdt
    │   └── rdt.zip
    └── secure

注意到 wwwroot/conf/exec 目錄下有一個文件 NOE77101.bin ,這就是要分析的韌體文件。使用binwalk命令查看文件內容,是一個Zlib類型的壓縮文件:

➜  exec binwalk NOE77101.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
901           0x385           Zlib compressed data, default compression

binwalk提取文件內容,binwalk會自動解壓文件,得到文件夾 _NOE77101.bin.extracted

➜  exec binwalk -e NOE77101.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
901           0x385           Zlib compressed data, default compression

➜  exec ls
NOE77101.bin            _NOE77101.bin.extracted kerVer

binwalk自動提取了文件到_NOE77101.bin.extracted目錄下,並對其進行解壓。此時文件夾下就有兩個文件,一個zlib和一個被解壓出來的:

➜  _NOE77101.bin.extracted ls
385      385.zlib

然後再用binwalk查看385文件:

➜  _NOE77101.bin.extracted binwalk 385

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2054252       0x1F586C        EST flat binary
2088936       0x1FDFE8        HTML document header
2108532       0x202C74        HTML document footer
2110048       0x203260        HTML document header
2115564       0x2047EC        HTML document footer
2119528       0x205768        XML document, version: "1.0"
2119796       0x205874        XML document, version: "1.0"
2119912       0x2058E8        XML document, version: "1.0"
2192512       0x217480        Base64 standard index table
2192580       0x2174C4        Base64 standard index table
2211604       0x21BF14        VxWorks WIND kernel version "2.5"
2225264       0x21F470        Copyright string: "Copyright Wind River Systems, Inc., 1984-2000"
2321952       0x236E20        Copyright string: "copyright_wind_river"
3118988       0x2F978C        Copyright string: "Copyright, Real-Time Innovations, Inc., 1991.  All rights reserved."
3126628       0x2FB564        Copyright string: "Copyright 1984-1996 Wind River Systems, Inc."
3153524       0x301E74        VxWorks symbol table, big endian, first entry: [type: function, code address: 0x1FF058, symbol address: 0x27655C]

得知文件是VxWorks韌體,符號表位置在0x301E74處,稍後會用到。

然後使用binwalk查看架構,得知是PowerPC big endian:

➜  _NOE77101.bin.extracted binwalk -A 385
....
2045960       0x1F3808        PowerPC big endian instructions, function epilogue
2045968       0x1F3810        PowerPC big endian instructions, function prologue
2046180       0x1F38E4        PowerPC big endian instructions, function epilogue
3150948       0x301464        PowerPC big endian instructions, function epilogue

之後用IDA打開385文件,在打開時設置架構:

Image.png

然後要求設置RAM和ROM,其實就是設置載入基地址:

Image.png

Image.png

Image.png

在IDA中無法識別出任何函數,需要在程式開頭位置按一下 「c」 鍵,就可以顯示部分函數,但沒有解析出所有的函數:

Image.png

Image.png

此時可以通過三種方式獲得載入基地址:

  • 通過跳轉表獲得基地址、通過字元串引用獲得基地址

韌體安全之載入地址分析 – 綠盟科技技術部落格

  • 使用IDA的Vxhunter插件

vxhunter/firmware_tools at master · PAGalaxyLab/vxhunter

這裡為了方便選擇Vxhunter插件,選擇python版本下載後複製到plugin文件夾下,然後運行插件:

Image.png

得到載入地址是0x10000:

Image.png

然後發現依然沒有解析函數,此時需要恢複函數名稱。使用IDA腳本:

#coding=utf-8
from idaapi import *
from idc import *

symbol_interval = 16 #符號表間隔
load_address = 0x10000 #韌體記憶體載入基址
symbol_table_start = 0x31eec4 + load_address   #符號表起始地址
symbol_table_end = 0x348114 + load_address #符號表結束地址
ea = symbol_table_start
eaEnd = symbol_table_end

while ea < eaEnd:
   offset = 0   #4個位元組為一組數據
   #將函數名指針位置的數據轉換為字元串
   create_strlit(get_wide_dword(ea-offset), BADADDR)
   #將函數名賦值給變數sName
   sName = get_strlit_contents(get_wide_dword(ea))
   print(sName)
   if sName:
       #開始修複函數名
       eaFunc = get_wide_dword(ea - offset +4)
       set_name(eaFunc, sName)
       create_insn(eaFunc)
       ida_funcs.add_func(eaFunc, BADADDR)
   ea += symbol_interval

程式碼中的符號表起始地址和符號表結束地址需要手動修改一下,可以在16進位編輯器中查看。在binwalk分析的時候得到符號表地址為0x301E74,然後在文件中找到這個位置,0x301E74即起始位置:

Image.png

符號表每0x10為一組,一直找到結束的位置0x3293a4:

Image.png

然後執行IDA腳本:

Image.png

最後恢復完成:

Image.png

usrAppInit函數中發現多處loginUserAdd添加用戶,這些字元串即後門帳號和密碼:

Image.png

總結

此韌體分析關鍵點在於確定程式基地址和如何恢復符號資訊,只要恢復了符號資訊就和閱讀源碼無異了。

References

韌體符號表恢復

//bbs.pediy.com/thread-266803-1.htm

韌體安全之載入地址分析 – 綠盟科技技術部落格

施耐德PLC乙太網模組後門賬戶解密 – 燈塔實驗室

//p1kk.github.io/2021/06/11/iot/施耐德 NOE771/