在后滲透或者取證階段,快速收集用戶信息是第一位的,今天這篇文章來記錄下關(guān)于telegram數(shù)據(jù)解密和賬號(hào)劫持的內(nèi)容,本文實(shí)驗(yàn)環(huán)境為最新版的telegram windows端5.1.7版本。
1. telegram的一些說明
1.1 常見特性
- 多端登錄: telegram支持多端同時(shí)登錄,這也是telegram能夠被賬號(hào)無感劫持的基礎(chǔ)
- 數(shù)據(jù)存儲(chǔ):telegram存儲(chǔ)在本地的數(shù)據(jù)都是加密的,包括文字、媒體和其他類型的數(shù)據(jù),但是在云端也會(huì)保存這些數(shù)據(jù),用于多端的數(shù)據(jù)同步
- 數(shù)據(jù)傳輸加密:telegram在普通對(duì)話時(shí)并不是端到端加密,而是客戶端到服務(wù)端加密,只有私密對(duì)話才會(huì)端到端加密,所以私密對(duì)話無法同步到不同的端上,見https://core.telegram.org/techfaq#q-how-does-server-client-encryption-work-in-mtproto
- Telegram的客戶端都是開源的,windows端的源碼地址:https://github.com/telegramdesktop/tdesktop
1.2 數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
telegram的默認(rèn)數(shù)據(jù)存儲(chǔ)在C:\Users\<YourUsername>\AppData\Roaming\Telegram Desktop\tdata目錄下,如果是potable文件,則數(shù)據(jù)存儲(chǔ)和在Telegram.exe同目錄下的tdata目錄,下面是我本地的目錄結(jié)構(gòu)

其中比較關(guān)鍵的幾個(gè)文件如下:
- key_datas:這個(gè)文件保存了賬戶基本信息,包括賬號(hào)數(shù)量,當(dāng)前處于active狀態(tài)的賬號(hào),更重要的是保存了其他文件解密的密鑰localKey
- settingss:這個(gè)文件保存了當(dāng)前客戶端的設(shè)置,比如語言、ip代理、下載目錄、軟件主題、軟件分辨率等等
- D877F783D5D3EF8Cs:這個(gè)文件保存了用戶的userId,以及與telegram云端進(jìn)行數(shù)據(jù)通信時(shí)所使用到的加密密鑰
- D877F783D5D3EF8C/maps:這個(gè)文件保存了用戶的基本信息,包括用戶userId,頭像,姓名,電話,還有一些配置或者資源文件的文件名
這個(gè)D877F783D5D3EF8C看起來很突兀,其實(shí)這是telegram的一套命名規(guī)則,第1個(gè)用戶相關(guān)數(shù)據(jù)保存在就是
data目錄
D877F783D5D3EF8Cs文件
D877F783D5D3EF8C文件夾
第二個(gè)用戶相關(guān)的數(shù)據(jù)保存在
data#2目錄
A7FDF864FBC10B77s文件
A7FDF864FBC10B77文件夾
第三個(gè)用戶相關(guān)的數(shù)據(jù)保存在
data#3目錄
F886DDC461824Fs文件
F886DDC461824F文件夾
依次類推。telegram客戶端會(huì)根據(jù)登錄的次序進(jìn)行編號(hào),分別為data,data#2,data#3,然后根據(jù)這個(gè)編號(hào)來生成目錄名稱,這部分代碼在Telegram\SourceFiles\storage\storage_account.cpp中,
使用python來構(gòu)造生成規(guī)則的代碼如下
import hashlib
def compute_data_name_key(dataname: str):
filekey = hashlib.md5(dataname.encode('utf8')).digest()[:8]
return file_to_to_str(filekey)
def file_to_to_str(filekey: bytes):
return ''.join(f'{b:X}'[::-1] for b in filekey)
if __name__=="__main__":
print(compute_data_name_key("data"))
print(compute_data_name_key("data#2"))
print(compute_data_name_key("data#3"))
print(compute_data_name_key("data#4"))
print(compute_data_name_key("data#5"))
print(compute_data_name_key("data#6"))
print(compute_data_name_key("data#7"))
結(jié)果為:
D877F783D5D3EF8C
A7FDF864FBC10B77
F886DDC461824F
C2B598D9127787
0CA814316818D8F6
45DFC5B510146D
93987688214F8E69
2. telegram數(shù)據(jù)解密
這一部分我的需求主要是解密賬戶信息,拿到登錄賬號(hào)的手機(jī)號(hào)、昵稱、用戶名等信息,所以暫不涉及對(duì)緩存數(shù)據(jù)比如媒體圖片視頻信息的解密。
3.1 key_datas文件
key_datas文件主要保存了兩個(gè)信息:
- 賬戶數(shù)量和當(dāng)前處于激活狀態(tài)的賬號(hào)編號(hào)
- 解密密鑰localKey,這是解密其他文件的前提
key_datas的解析在解密流程在Telegram\SourceFiles\storage\storage_domain.cpp的startModern函數(shù)中,文件結(jié)構(gòu)為:4字節(jié)的魔數(shù)+4字節(jié)的版本號(hào)+加密data+最后16字節(jié)的hashsum,解析文件結(jié)構(gòu)的代碼在Telegram\SourceFiles\storage\details\storage_file_utilities.cpp
其中:
- 0-4字節(jié)的魔數(shù)固定為
TDF$,這是判斷文件類型的標(biāo)志 - 4-8字節(jié)是version,取出來轉(zhuǎn)int類型即可
- [8:-16]是加密data
- 最后16字節(jié)是hashsum,這是為了校驗(yàn)文件的完整性
解密加密data的步驟如下:
1.解析Data,得到salt, keyEncrypted, infoEncrypted
2.調(diào)用createLocalKey(),根據(jù)salt和passcode生成一個(gè)本地密鑰passcode_key生成passcodeKey
3 調(diào)用DecryptLocal()和密鑰導(dǎo)出函數(shù),使用導(dǎo)出密鑰解密keyEncrypted,得到localKey
4.調(diào)用DecryptLocal(),使用localkey解密infoEncrypted,得到info
上面的passcode是telegram隱私設(shè)置里的local passcode,默認(rèn)為空,具體的邏輯看源代碼即可,下面是解析完的結(jié)果:

3.2 settingss文件解密
settingss文件的結(jié)構(gòu)和key_datas文件一樣,也是:4字節(jié)的魔數(shù)+4字節(jié)的版本號(hào)+加密data+最后16字節(jié)的hashsum
其中加密data的解析步驟在Telegram\SourceFiles\storage\localstorage.cpp的start函數(shù)中,簡略步驟如下:
1. 解析data,得到 salt 和 settingsEncrypted
2. 調(diào)用CreateLegacyLocalKey()根據(jù)salt生成加密密鑰SettingsKey
3. 調(diào)用DecryptLocal()解密settingsEncrypted得到settings
4. 使用ReadSetting解析settings,形成key和value的對(duì)應(yīng)關(guān)系
需要注意的是第4步驟的解析過程,key和value的關(guān)系在Telegram\SourceFiles\storage\details\storage_settings_scheme.cpp的ReadSetting函數(shù)中,算法還原時(shí)如果有問題可以仔細(xì)看下這里。
最終結(jié)果如下,有一些參數(shù)比如dbiFallbackProductionConfig這些,需要二次解析,這里我暫時(shí)用不著所以就不解析了

3.3 7FDF864FBC10B77s
文件的結(jié)構(gòu)和上面一樣,也是4字節(jié)的魔數(shù)+4字節(jié)的版本號(hào)+加密data+最后16字節(jié)的hashsum
加密data的解析過程如下:
1. 調(diào)用DecryptLocal(),解密data,其中key為上面提到的localKey
2. 調(diào)用ReadSetting()解析上一步解密后的data,形成key和value的對(duì)應(yīng)關(guān)系
3. 調(diào)用setMtpAuthorization()解析得到userId和 客戶端-服務(wù)端 通信密鑰

這里的userID在軟件上是看不到的,可以給@userinfobot發(fā)送信息查看自己的userId:

3.4 7FDF864FBC10B77/maps
maps文件是我主要需要解析的文件,這個(gè)文件可以拿到用戶的基本信息,包括用戶名、手機(jī)號(hào)等。還是一樣先解析成4字節(jié)的魔數(shù)+4字節(jié)的版本號(hào)+加密data+最后16字節(jié)的hashsum
然后對(duì)data進(jìn)行解密
1. 使用decryptLocal()對(duì)data進(jìn)行解密,密鑰是localKey
2. 使用readMapWith()對(duì)解密后的data進(jìn)行解析,形成key和value的對(duì)應(yīng)關(guān)系
這部分代碼在Telegram\SourceFiles\storage\storage_account.cpp,主要是對(duì)lskSelfSerialized的二次解析比較費(fèi)勁,用戶信息都存在這個(gè)blockid里。最終結(jié)果如下:

3. telegram賬號(hào)劫持
telegram的賬號(hào)劫持,就是將受害者的登錄態(tài)session文件給復(fù)制到本地,然后就可以在本地登錄對(duì)方賬號(hào),劫持時(shí)只需要復(fù)制下面三個(gè)文件即可
key_datas
D877F783D5D3EF8Cs
D877F783D5D3EF8C/map
如果受害者有兩個(gè)賬戶,只需要追加下面兩個(gè)文件即可,以此類推
A7FDF864FBC10B77s
A7FDF864FBC10B77/map
復(fù)現(xiàn)步驟如下:
- 清空本地telegram的tdata文件夾
- 打開本地的telegram,重新生成tdata文件目錄結(jié)構(gòu)
- 將受害者的文件,復(fù)制覆蓋到本地,重新打開telegram即可實(shí)現(xiàn)賬號(hào)劫持
劫持時(shí)對(duì)方是無感的,需要注意下面幾個(gè)點(diǎn):
- 本地的telegram最好使用最新版,以保證兼容性
- 如果受害者設(shè)置了local passcode(注意這里并不是Two-Step Verification),則賬號(hào)劫持后也需要輸入鎖定密碼,似乎目前只能通過爆破的手段來獲取passcode,因?yàn)楸容^小眾,故未研究此場景,劫持后會(huì)彈出下圖所示的驗(yàn)證:

4. telegram安全措施
為避免賬號(hào)劫持以及減少被盜后的危害,可以采取下面的措施
- 設(shè)置local passcode
- 日常溝通使用端到端加密,但是已經(jīng)2024年了,windows客戶端還不支持雙向加密
- 定期檢查在線登錄設(shè)備
浙公網(wǎng)安備 33010602011771號(hào)