Skip to main content

當你對NAS或Linux OS(怕被查水表)做了全扇區加密(FDE),其實這是用了Linux Unified Key Setup 簡稱LUKS.
但做了這加密後,萬一系統出了狀況,硬碟損壞,需要資料救援,或忘記密碼等 又會是怎樣的狀況?
這篇將會做全面分析。

對於全扇區FDE架構建議先參考 OSSLab這篇文章

首先我們要瞭解現代NAS 陣列與分區與架構如圖

(圖引用自 http://www.hivestream.de/tag/luks.html)

在一般NAS下 多顆HDD mdadm 組好的md ,再分區,前面通常會分割給NAS作業系統,會割最大塊的數據分區會使用LVM來分割
回顧一下LVM 
Physical Volume, PV, 實體捲軸
Volume Group, VG, 捲軸群組:將許多的 PV 整合成為一個捲軸群組 (VG)
Logical Volume, LV, 邏輯捲軸:最終將 VG 再切割出類似 partition 的 LV 即是可使用的裝置了
最大數據分區直接切PV ,PV 組VG 

pvcreate /dev/md1 Physical volume "/dev/md1" successfully created vgcreate vgssd /dev/md1 Volume group "vghdd" successfully created lvcreate -l 100%VG -n user1 vgsdd

對sda2 分區做LUKS 加密格式初始化

cryptsetup luksFormat /dev/sda2

對VG做LUKS 加密格式初始化 ,通常NAS加密Volume就是這樣格式化的
如果對整個MD加密,那當Raid參數丟失,因為沒有其他明文文件系統.推測Raid參數需要額外處理

cryptsetup luksFormat /dev/vgssd/user1

掛載LUKS 跟分割成ext4 檔案系統,當然要割成其他檔案系統如BTRFS也沒問題.

cryptsetup open /dev/vgssd/user1 vgssd-user1 mkfs.ext4 /dev/mapper/vgssd-user1

在全扇區加密下的檔案分區在已經格式化完畢完工.

那NAS 全扇區加密對於資料救援會有何影響? 我們都知道全扇區加密 ,一定要有地方放metadata內有被加密的密鑰,

LUKS 是將明文數據切割成若干 同樣大小Blocks .
使用同一個對稱密鑰塊和確定的算法對每個數據塊進行加解密
所以在LUKS metadata完整之下 ,資料恢復會是這樣的
1.物理硬碟壞軌:如果有做Raid 1或5 或6,從其他顆正常扇區mirror 或XOR補齊.但如果小量整體,不會影響數據太大.
2.物理硬碟整顆損壞:如果有做Raid 1或5 或6,從其他顆正常扇區mirror 或XOR補.如果沒有則需要將單顆硬碟整顆修理好.
3.檔案刪除ext4:從日誌系統撈inode,或使用檔案碎片搜索法一樣可以正常運作.
4.分區掉失: 一樣可以資料恢復

如果有先組Raid,那Raid MD需要下面參數,整個MD資料才能正確無誤
1.走向方法
2.Stripe size
3.硬碟順序

所以假設Raid參數也丟失時候,就要利用文件系統來對Raid參數的逆向推測.
如果MD內留有未加密分區,則可以文件系統順利推導回去Raid參數.
但如果做了全扇區加密,那該怎推敲Raid參數?

此時利用LUKS metadata ,來推算出Master Key .再對每個單顆硬碟做扇區解密轉換,才可求得明文文件系統
再利用文件系統特性參數來拼湊出Raid參數.(本文最後有寫推導方法與轉換指令)

但假設是LUKS有問題狀況時候,我們要怎樣來做資料救援取得資料?
我們先來看整顆硬碟上LUKS架構

  • volume (or partition) header (208 byte)
  • 8 x key slots (48 byte*8)
  • key material(加密的split master key)

以上都為LUKS metadata(Header)

  • encrypted (volume) data:被加密的密文數據

第一 一定要先備份LUKS metdata(Header)指令如下 

cryptsetup luksHeaderBackup <device> --header-backup-file <file>

查看LUKS  volume (or partition)  Header與Key slot

#cryptsetup luksDump /dev/sda2
LUKS header information for /dev/sda2

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
MK salt:        xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
                xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
MK iterations:  371000
UUID:           28c39f66-dcc3-4488-bd54-11ba239f7e68

Key Slot 0: ENABLED
        Iterations:             2968115
        Salt:                   xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
                                xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: ENABLED
        Iterations:             2968115
        Salt:                   xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
                                xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 
        Key material offset:    264
        AF stripes:             4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

LUKS volume (or partition) header +key slot 為 592 bytes 結構如下 建議上下核對 以下為big eddian

Offset Size(byte) Value Description
0 6 “LUKS\xba\xbe” 簽名  ASCII 顯示為 “LUKS..”
6 2 1 版本
8 32   加密方法 (Cipher name) etc:AES
Contains an ASCII string with an end-of-string character
40 32   加密模式 (Cipher mode) etc:xts-plain64
Contains an ASCII string with an end-of-string character
72 32   哈希模式 example:sha256
用於用戶密鑰計算和抗碎片分析(AF)擴散的散列方法
Contains an ASCII string with an end-of-string character
104 4   加密卷開始扇區 (Payload offset)
108 4   Master Key大小 (注意MK bits顯示為bit 通常為128,256,512) 
Contains the size of the key in bytes
112 20   Master Key digiest
132 32   Master key salt
164 4   Master key 迭代次數(MK iteration)
168 40   卷標識符(UUID)
包含帶有字符串結尾字符的ASCII字符串,該字符串由小寫的UUID組成
208 8 x 48   Key slots 48 bytes總共有8個

 

Key slot

Key slot is 48 bytes 內容如下

Offset Size(byte) Value Description
0 4   狀態 (of key slot)
0x0000dead ⇒ inactive (dead)
0x00ac71f3 ⇒ active
4 4   Key material 迭代次數 (Iterations)
8 32   Key material salt
40 4   Key material 開始扇區 (encrypted SMK開始位置)
44 4   每個 (anti-forensic) stripes有多少個Key material
(AF stripes)

主密鑰Master Key:(MK)這是最關鍵的密鑰,如果記憶體中撈的出來你也不用需要User 密碼跟LUKS Header),直接就可以解開加密的數據
                                  MK大小值取決於卷標頭中MK bits 通常是128或256或512 bit。

要特別注意的,這跟WD全扇區硬體加密硬碟一樣,
當變更用戶密碼時候.MK主密鑰不會改變.變動的是Key material(encrypted SMK)

以下為LUKS 加密架構


下面為 LUKS 初始加密時寫入Header  Pseudo code

下面為LUKS metadata(Header+Key material)+用戶密碼的 ,完成mk驗證的Pseudo code

忘了用戶密碼怎辦?
一.由於LUKS沒有限制輸入密碼次數因此可以寫script嘗試爆破
下面參考自 https://nmattia.com/posts/2017-03-05-crack-luks-stutter-gnu-parallel.html

crack_maybe=$(cat <<'EOF'
	echo PASS | cryptsetup open --test-passphrase ./encrypted-file
	rc=$?
	if [ "$rc" -ne "2" ]; then
		echo "return code $rc on input PASS"
		exit 255
	fi
EOF
)

我們將過程存儲在一些shell變量中,以便我們可以將它傳遞給xargs,例如:

stutter將潛在的密碼短語提供給xargs,crack_maybe在PASS用潛在密碼短語替換所有出現的密碼後調用。如果cryptsetup返回任何其他內容2,我們退出exit 255,這基本上是告訴xargs停止的唯一方法(否則程式會繼續跑)  

二. bruteforce-luks (GitHub)是用調用cryptsetup API爆破, 速度有好一點

不過上面二個方法當然不夠有效率 
來看看hastcat爆破LUKS的思路…..

來從看一下LUKS 解密架構

第一次PBKDF2 跟AF轉換後就有有主密鑰,就可以開始嘗試做解密攻擊.
而不需要如正統流程再跑一次PBKDF2.這非常耗時間..
hashcat發現LUKS加密的過的數據會像是隨機數據
因此對數據區做熵檢查,如果熵低於某個閾值,可以假設密碼是正確的
要鏡像超過2MB超過LUKS metadata,就是因為需要包含數據區.

這思路很酷,以資料救援設備MRT來講.爆破FDE密鑰是利用驗證第0扇區 末端magic number為55AA
Hastcat開發者ATOM非常自豪他的LUKS破解思路,他認為比起市面上商業軟體如Passware都快了20倍以上.

Hashcat破解LUKS指令

首先要取得LUKS Header 2.1MB (是的 要比LUKS metadata再大一點)

dd if = / dev / XXXX of = header.luks bs = 512 count = 4097
./hashcat-3.5.0/hashcat64.bin -m 14600 -a 0 -w 3 header.luks Dictionary.txt -o luks_password.txt

-m = hash method – 14600 for LUK encryption
-a = Crack method – 0 for standard dictionary (3 for bruteforce)
-w = resource allocation – 3 for high
header.luks = 加密分區檔頭
Dictionary.txt = dictionary
-o = output luks_password.txt 
破解成功後.就可從luks_password.txt 的到用戶密碼.
爆破LUKS其實很困難,配上1070顯卡也才3000 Hash/s 上下
因此一般狀況下不必擔心LUKS 用戶密碼被破解

如果電腦沒有關機下 LUKS 還有其他破解方式:
1.假設是加密方法是AES,那可做記憶體鑑識 ,將記憶體DUMP ,使用findaes 找出在記憶體中的MK ,由於取得是MK就直接可以用了.
你要知道Ciper mode ,並且還有加密區大小..

echo "0 <size> crypt aes-xts-plain64 <key> 0 </dev/drive> 4096" | sudo dmsetup create luks-volume

比較有趣的是,這個方法在Mount時候就可以忽略到LUKS header..

那當LUKS metadata(Header+ encrypted SMK)如果遭遇硬碟扇區損壞跟惡意擦除
(通常是上門查水表,駭客立刻消滅密鑰,讓警方無法做數位鑑識) 這會是怎樣狀況?

先來看看破壞方法,比如sdX1為LUKS分區 下DD擦除 前面2MB就可.

dd if=/dev/urandom of=/dev/sdX1 bs=512 count=20480

這樣還有機會做資料救援嗎?

看一下主密鑰MK 是怎樣產生的

pwd−PBKDF2ed = PBKDF2(pwd,ks.salt,ks.iteration−count
                       masterKeyLength )
read from partition (encryptedKey, //destination
                     ks.key−material−offset, //sector number
                     masterKeyLength*ks.stripes) //number of bytes
splitKey =decrypt(phdr.cipherSpec, //cipher spec .
                  pwd−PBKDF2ed,//key
                  encryptedKey,//content
                  encrypted)   //content length
masterKeyCandidate = AFmerge (splitKey,masterkeyLength ,
                              ks.stripes)

這會跟Hashcat不一樣 ,這時反而有User Key  (pwd) 
只求破解用masterKeyCandidate就可以做MK (沒做第二次PBKDF2驗證)

所以只需要下面
以下這二個 是最必備的
1.encryptedKey:Key material ,encrypted SMK 以最上面為例,大小4000 x 256bit=125KBytes
2.ks.salt:Key slot 中的Key material salt大小32 byte

以下為好推測的 同一款NAS 版本下應該是一樣
1.masterKeyLength 這好推測128 ,256,512bit
2.cipherSpec:cbc,ecb,xts
3.ks.iteration−count :Key material 迭代次數
4.ks.key−material−offset:Key slot中的Key material 開始扇區 (encrypted SMK開始位置)
5.ks.stripes:key slot Stripe 數.
6.encrypted :Material Key 大小=masterKeyLength *ks.stripes

算出 MK 一樣檢查對數據區檢查熵,一定低於某個閾值.就應該為正確MK
求得MK後,一樣直接用crypt 來解密

echo "0 "size" crypt ciphername+cipherSpec key 0 "/dev/drive" 4096" | sudo dmsetup create luks-volum

前述中若NAS Raid參數丟失,而Raid MD中只有單一加密分區,LUKS metadata也完整時,也是用上面方法生成MK先,
用上面指令做單顆硬碟解密,再根據解密文件系統分析推導出Raid參數.

看到這,確實當Key material (encrypted SMK),ks.salt(Key slot 中的Key material salt) 被擦除掉或是這部位硬碟扇區損壞.
也沒有從記憶體取中取得MK時.是無法解密資料的.

結論:
會寫這篇文其實是因為客戶遇到這樣狀況詢問我們,
一台6 Bay NAS做了加密,無法掛載資料,當初拿給原廠Support Team,但原廠也沒辦法作處理.
之後也不確定Raid組態跟LUKS Header是否還在.
(這方面來講,原廠其實不該負責客戶資料,或是客戶應該要做全硬碟備份先,再給原廠處理.)

OSSLab之前會使用LUKS攻擊工具但不知道其原理,
這次研究整合必須一次做到
1.一般NAS架構上套件安裝流程才會知道架構.
2.加密程式原始碼與演算法架構
3.多種破解手法與破解程式經驗與思路

最終編寫自己程式,才有機會做如此高難度的資安與資料恢復處理.

上面圖引用自與參考
https://github.com/libyal/libluksde
https://hashcat.net/forum/thread-6225.html
http://www.hivestream.de/tag/luks.html
http://netinfo-security.org/CN/abstract/abstract5917.shtml#
https://www.freebuf.com/articles/database/181010.html
https://blog.pnb.io/2018/02/bruteforcing-linux-full-disk-encryption.html
https://blog.appsecco.com/breaking-full-disk-encryption-from-a-memory-dump-5a868c4fc81e

Thx Chang

Author Thx Chang

More posts by Thx Chang