Blue Team Notes
Blue Team Notes
A collection of one-liners, small scripts, and some useful tips for blue team work.
I've included screenshots where possible so you know what you're getting.
I hope the Blue Team Notes help you catch an adversary, thwart an attack, or even just helps you
learn. If you've benefited from the Blue Team Notes, would you kindly consider making a
donation to one or two charities.
Donate as much or little money as you like, of course. I have some UK charities you could donate
to: Great Ormond Street - Children's hospital, Cancer Research, and Feeding Britain - food
charity
Table of Contents
Shell Style
Windows
OS Queries
Account Queries
Service Queries
Network Queries
Remoting Queries
Firewall Queries
SMB Queries
Process Queries
Recurring Task Queries
File Queries
Registry Queries
Driver Queries
DLL Queries
AV Queries
Log Queries
Powershell Tips
Linux
Bash History
Grep and Ack
Processes and Networks
Files
Bash Tips
MacOS
Reading .plist files
Quarantine Events
Install History
Most Recently Used (MRU)
Audit Logs
Command line history
WHOMST is in the Admin group
Persistence locations
Transparency, Consent, and Control (TCC)
Built-In Security Mechanisms
Malware
Rapid Malware Analysis
Unquarantine Malware
Process Monitor
Hash Check Malware
Decoding Powershell
SOC
Sigma Converter
SOC Prime
Honeypots
Basic Honeypots
Network Traffic
Capture Traffic
TShark
Extracting Stuff
PCAP Analysis IRL
Digital Forensics
Volatility
Quick Forensics
Chainsaw
Browser History
Which logs to pull in an incident
USBs
Reg Ripper
As you scroll along, it's easy to lose orientation. Wherever you are in the Blue Team Notes, if you
look to the top-left of the readme you'll see a little icon. This is a small table of contents, and it
will help you figure out where you are, where you've been, and where you're going
As you go through sections, you may notice the arrowhead that says 'section contents'. I have
nestled the sub-headings in these, to make life a bit easier.
Shell Style
section contents
CMD
Pwsh
##open .bashrc
sudo nano .bashrc
#https://www.howtogeek.com/307701/how-to-customize-and-colorize-your-bash-prompt/
##date, time, colour, and parent+child directory only, and -> promptt
PS1='\[\033[00;35m\][`date +"%d-%b-%y %T %Z"]` ${PWD#"${PWD%/*/*}/"}\n\[\033[01;36m
##begin purple #year,month,day,time,timezone #show last 2 dir #next line, cya
#restart the bash source
source ~/.bashrc
Windows
section contents
I've generally used these Powershell queries with Velociraptor, which can query thousands of
endpoints at once.
OS Queries
section contents
([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname
Hardware Info
If you want, you can get Hardware, BIOS, and Disk Space info of a machine
## Let's calculate an individual directory, C:\Sysmon, and compare with disk memory
$size = (gci c:\sysmon | measure Length -s).sum / 1Gb;
write-host " Sysmon Directory in Gigs: $size";
$free = gcim -ClassName Win32_LogicalDisk | select @{L='FreeSpaceGB';E={"{0:N2}" -f
echo "$free";
$cap = gcim -ClassName Win32_LogicalDisk | select @{L="Capacity";E={"{0:N2}" -f (
echo "$cap"
Time info
Human Readable
This one is great for doing comparisons between two strings of time
[Xml.XmlConvert]::ToString((Get-Date).ToUniversalTime(), [System.Xml.XmlDateTimeSeri
Get Patches
get-hotfix|
select-object HotFixID,InstalledOn|
Sort-Object -Descending -property InstalledOn|
format-table -autosize
This happened to me during the March 2021 situation with Microsoft Exchange's ProxyLogon.
The sysadmin swore blind they had patched the server, but neither systeminfo of get-
hotfix was returning with the correct KB patch.
First identify the ID number of the patch you want. And then find the dedicated Microsoft
support page for it.
For demonstration purposes, let's take KB5001078 and it's corresponding support page. You'll
be fine just googling the patch ID number.
On Host
Let us now assume you don't know the path to this file on your host machine. You will have to
recursively search for the file location. It's a fair bet that the file will be in C:\Windows\ (but not
always), so lets' recursively look for EventsInstaller.dll
$file = 'EventsInstaller.dll'; $directory = 'C:\windows' ;
gci -Path $directory -Filter $file -Recurse -force|
sort-object -descending -property LastWriteTimeUtc | fl *
We'll get a lot of information here, but we're really concerned with is the section around the
various times. As we sort by the LastWriteTimeUtc , the top result should in theory be the
latest file of that name...but this is not always true.
Discrepencies
I've noticed that sometimes there is a couple days discrepency between dates.
For example in our screenshot, on the left Microsoft's support page supposes the
EventsInstaller.dll was written on the 13th January 2021. And yet our host on the right side
of the screenshot comes up as the 14th January 2021. This is fine though, you've got that file
don't sweat it.
Account Queries
section contents
Change the AddDays field to more or less days if you want. Right now set to seven days.
The 'when Created' field is great for noticing some inconsistencies. For example, how often are
users created at 2am?
import-module ActiveDirectory;
$When = ((Get-Date).AddDays(-7)).Date;
Get-ADUser -Filter {whenCreated -ge $When} -Properties whenCreated |
sort whenCreated -descending
import-module ActiveDirectory;
Get-ADUser -Identity HamBurglar -Properties *
qwinsta
#or
quser
If you want to find every single user logged in on your Active Directory, with the machine they
are also signed in to.
Evict User
You may need to evict a user from a session - perhaps you can see an adversary has been able
to steal a user's creds and is leveraging their account to traverse your environment
From the above instance, we may want to force a user to have a new password - one the
adversary does not have
Good if you need to quickly eject an account from a specific group, like administrators or remote
management.
$user = "erochester"
remove-adgroupmember -identity Administrators -members $User -verbose -confirm:$fals
Good for depriving adversary of pass they may have got. Also good for re-establishing trust if
machine is kicked out of domain trust for reasons(?)
Reset-ComputerMachinePassword
Instead, PowerShell in Windows 10 saves the last 4096 commands in a particular file. On an
endpoint, we can run a quick loop that will print the full path of the history file - showing which
users history it is showing - and then show the contents of that users' PwSh commands
c:\windows\system32\config\systemprofile\appdata\roaming\microsoft\windows\powershel
Service Queries
section contents
Show Services
Let's get all the services and sort by what's running
get-service|Select Name,DisplayName,Status|
sort status -descending | ft -Property * -AutoSize|
Out-String -Width 4096
$Name = "eventlog";
gwmi -Class Win32_Service -Filter "Name = '$Name' " | fl *
#or this, but you get less information compared to the one about tbh
get-service -name "eventlog" | fl *
Kill a service
# Grep out results from System32 to reduce noise, though keep in mind adversaries ca
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\services\*" |
where ImagePath -notlike "*System32*" |
ft PSChildName, ImagePath -autosize | out-string -width 800
Network Queries
section contents
I have a neat one-liner for you. This will show you the local IP and port, the remote IP andport,
the process name, and the underlying executable of the process!
You could just use netstat -b , which gives you SOME of this data
Get-NetTCPConnection |
select LocalAddress,localport,remoteaddress,remoteport,state,@{name="process";Expres
sort Remoteaddress -Descending | ft -wrap -autosize
#### you can search/filter by the commandline process, but it will come out janky.
##### in the final field we're searching by `anydesk`
Get-NetTCPConnection |
select LocalAddress,localport,remoteaddress,remoteport,state,@{name="process";Expres
| Select-String -Pattern 'anydesk'
######## Bound to catch bad guys or your moneyback guaranteed!!!!
If you see suspicious IP address in any of the above, then I would hone in on it
Get-NetTCPConnection |
? {($_.RemoteAddress -eq "1.2.3.4")} |
select-object -property state, creationtime, localport,remoteport | ft -autosize
Kill a connection
There's probably a better way to do this. But essentially, get the tcp connection that has the
specific remote IPv4/6 you want to kill. It will collect the OwningProcess. From here, get-process
then filters for those owningprocess ID numbers. And then it will stop said process. Bit clunky
gc -tail 4 "C:\Windows\System32\Drivers\etc\hosts"
#the above gets the most important bit of the hosts file. If you want more, try this
gc "C:\Windows\System32\Drivers\etc\hosts"
Investigate DNS
The above command will likely return a lot of results you don't really need about the
communication between 'trusted' endpoints and servers. We can filter these 'trusted'
hostnames out with regex, until we're left with less common results.
On the second line of the below code, change up and insert the regex that will filter out your
machines. For example, if your machines are generally called WrkSt1001.corp.local, or
ServStFAX.corp.local, you can regex out that first poriton so it will exclude any and all machines
that share this - so workst|servst would do the job. You don't need to wildcard here.
Be careful though. If you are too generic and liberal, you may end up filtering out malicious and
important results. It's bettter to be a bit specific, and drill down further to amake sure you aren't
filtering out important info. So for example, I wouldn't suggest filtering out short combos of
letters or numbers ae|ou|34|
Get-DnsClientCache |
? Entry -NotMatch "workst|servst|memes|kerb|ws|ocsp" |
out-string -width 1000
If there's an IP you're sus of, you can always take it to WHOIS or VirusTotal, as well see for other
instances it appears in your network and what's up to whilst it's interacting there.
IPv6
Since Windows Vitsa, the Windows OS prioritises IPv6 over IPv4. This lends itself to man-in-the-
middle attacks, you can find some more info on exploitation here
You probably don't want to switch IPv6 straight off. And if you DO want to, then it's probably
better at a DHCP level. But what we can do is change how the OS will prioritise the IPv6 over
IPv4.
#check if machine prioritises IPv6
ping $env:COMPUTERNAME -n 4 # if this returns an IPv6, the machine prioritises this
#If this reg already exists and has values, change the value
Set-ItemProperty “HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\” -Name
BITS Queries
Get-BitsTransfer|
fl DisplayName,JobState,TransferType,FileList, OwnerAccount,BytesTransferred,Creatio
## filter out common bits jobs in your enviro, ones below are just an example, you w
Get-BitsTransfer|
| ? displayname -notmatch "WU|Office|Dell_Asimov|configjson" |
fl DisplayName,JobState,TransferType,FileList, OwnerAccount,BytesTransferred,Creatio
## Hunt down BITS transfers that are UPLOADING, which may be sign of data exfil
Get-BitsTransfer|
? TransferType -match "Upload" |
fl DisplayName,JobState,TransferType,FileList, OwnerAccount,BytesTransferred,Creatio
Remoting Queries
section contents
Powershell Remoting
Get Powershell sessions created
Get-PSSession
Remoting Permissions
Get-PSSessionConfiguration |
fl Name, PSVersion, Permission
Check Constrained Language
To be honest, constrained language mode in Powershell can be trivally easy to mitigate for an
adversary. And it's difficult to implement persistently. But anyway. You can use this quick
variable to confirm if a machine has a constrained language mode for pwsh.
$ExecutionContext.SessionState.LanguageMode
RDP settings
You can check if RDP capability is permissioned on an endpoint
Let's call on one of the RDP logs, and filter for event ID 1149, which means a RDP connection has
been made. Then let's filter out any IPv4 addresses that begin with 10.200, as this is the internal
IP schema. Perhaps I want to hunt down public IP addresses, as this would suggest the RDP is
exposed to the internet on the machine and an adversary has connected with correct
credentials!!!
Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational
Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx
qwinsta
You can read here about how to evict a malicious user from a session and change the creds
rapidly to deny them future access
Check Certificates
You will be dissapointed how many certificates are expired but still in use. Use the -
ExpiringInDays flag
Firewall Queries
section contents
(Get-NetFirewallProfile).name
Not likely to be too useful getting all of this information raw, so add plenty of filters
Get-NetFirewallProfile -Name Public | Get-NetFirewallRule
##filtering it to only show rules that are actually enabled
Get-NetFirewallProfile -Name Public | Get-NetFirewallRule | ? Enabled -eq "true"
Code Red
Isolate Endpoint
Disconnect network adaptor, firewall the fuck out of an endpoint, and display warning box
In the penultimate and final line, you can change the text and title that will pop up for the user
SMB Queries
section contents
List Shares
Get-SMBShare
List client-to-server SMB Connections
Dialect just means verison. SMB3, SMB2 etc
Get-SmbConnection
#just show SMB Versions being used. Great for enumeration flaws in enviro - i.e, smb
Get-SmbConnection |
select Dialect, Servername, Sharename | sort Dialect
Remove an SMB Share
Process Queries
section contents
You could just use netstat -b , which gives you SOME of this data
But instead, try this bad boy on for size:
Get-NetTCPConnection |
select LocalAddress,localport,remoteaddress,remoteport,state,@{name="process";Expres
sort Remoteaddress -Descending | ft -wrap -autosize
get-process * -Includeusername
Try this one if you're hunting down suspicious processes from users
gwmi win32_process |
Select Name,@{n='Owner';e={$_.GetOwner().User}},CommandLine |
sort Name -unique -descending | Sort Owner | ft -wrap -autosize
Get specific info about the full path binary that a process is running
gwmi win32_process |
Select Name,ProcessID,@{n='Owner';e={$_.GetOwner().User}},CommandLine |
sort name | ft -wrap -autosize | out-string
$process = "memes";
if (ps | where-object ProcessName -Match "$process") {Write-Host "$process successf
I get mixed results with this command but it's supposed to give the percent of CPU usage. I
need to work on this, but I'm putting it in here so the world may bare wittness to my smooth
brain.
$ProcessName = "symon" ;
$ProcessName = (Get-Process -Id $ProcessPID).Name;
$CpuCores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors;
$Samples = (Get-Counter "\Process($Processname*)\% Processor Time").CounterSamples;
$Samples | Select `InstanceName,@{Name="CPU %";Expression={[Decimal]::Round(($_.Cook
Process Tree
You can download the PsList exe from Sysinternals
Fire it off with the -t flag to create a parent-child tree of the processes
Recurring Task Queries
section contents
And a command to get granularity behind the schtask requires you to give the taskpath. Tasks
with more than one taskpath will throw an error here
$task = "CacheTask";
get-scheduledtask -taskpath (Get-ScheduledTask -Taskname "$task").taskpath | Export-
#this isn't the way the microsoft docs advise.
##But I prefer this, as it means I don't need to go and get the taskpath when I
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tree
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tasks
C:\Windows\System32\Tasks
C:\Windows\Tasks
C:\windows\SysWOW64\Tasks\
You can compare the above for tasks missing from the C:\Windows directories, but present in
the Registry.
# From my man Anthony Smith - https://www.linkedin.com/in/anthony-c-smith/
Threat actors have been known to manipulate scheduled tasks in such a way that Task
Scheduler no longer has visibility of the recuring task.
Shout out to my man @themalwareguy for the $fixedstring line that regexes in/out good/bad
characters.
Once you've deployed the above loop, and zoned in on a binary / one-liner that seems sus, you
can query it in the other Registry location
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tasks\{$ID}
HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tree\$Name
HKLM\software\classes\exefile\shell\open\command
c:\Users\*\appdata\roaming\microsoft\windows\start menu\programs\startup
Querying that last one in more detail, you have some interesting options
#Extract from the path User, Exe, and print machine name
(gci "c:\Users\*\appdata\roaming\microsoft\windows\start menu\programs\startup\*").f
foreach-object {$data = $_.split("\\");write-output "$($data[2]), $($data[10]), $(ho
Adversaries can link persistence mechanisms to be activated to a users' login via the registry
HKEY_CURRENT_USER\Environment -UserInitMprLogonScript
Programs at Powershell
Adversaries can link their persistence mechanisms to a PowerShell profile, executing their malice
every time you start PowerShell
You can get a bit more clever with this if you want
Stolen Links
Adversaries can insert their malice into shortcuts. They can do it in clever ways, so that the
application will still run but at the same time their malice will also execute when you click on the
application
For demo purposes, below we have Microsoft Edge that has been hijacked to execute calc on
execution.
We can specifically query all Microsoft Edge's shortcuts to find this
Get-CimInstance Win32_ShortcutFile |
? FileName -match 'edge' |
fl FileName,Name,Target, LastModified
This doesn't scale however, as you will not know the specific shortcut that the adversary has
manipulated. So instead, sort by the LastModified date
Get-CimInstance Win32_ShortcutFile |
sort LastModified -desc |
fl FileName,Name,Target, LastModified
Hunt LNKs at scale
This above will output a LOT, however. You may want to only show results for anything
LastModified after a certain date. Lets ask to only see things modified in the year 2022 onwards
Get-CimInstance Win32_ShortcutFile |
where-object {$_.lastmodified -gt [datetime]::parse("01/01/2022")} |
sort LastModified -desc | fl FileName,Name,Target, LastModified
Scheduled Jobs
Surprisingly, not many people know about Scheduled Jobs. They're not anything too strange or
different, they're just scheduled tasks that are specificially powershell.
I've written about a real life encounter I had during an incident, where the adversary had
leveraged a PowerShell scheduled job to execute their malice at an oppertune time
Get-ScheduledJob
# pipe to | fl * for greater granularity
Get detail behind scheduled jobs
Get-ScheduledJob | Get-JobTrigger |
Ft -Property @{Label="ScheduledJob";Expression={$_.JobDefinition.Name}},ID,Enabled,
#pipe to fl or ft, whatever you like the look of more in the screenshot
Kill job
Finding it
Get-CimInstance comes out cleaner, but you can always rely on the alternate Get-WMIObject
## OR
Now we've identified the evil WMI persistence, let us be rid of it!
We can specify the Name as EVIL as that's what it was called across the three services.
Whatever your persistence calls itself, change the name for that
#notice this time, we use the abbrevated version of CIM and WMI
You may see WMI and CIM talked about together, whether on the internet or on in the Blue Team
Notes here.
CIM is a standard for language for vendor-side management of a lot of the physical and digital
mechanics of what makes a computer tick. WMIC was and is Microsoft's interpretation of CIM.
Run Keys
Run and RunOnce registry entries will run tasks on startup. Specifically:
Run reg keys will run the task every time there's a login.
RunOnce reg kgeys will run the taks once and then self-delete keys.
If a RunOnce key has a name with an exclemation mark (!likethis) then it will self-delete
IF a RunOnce key has a name with an asterik (* LikeDIS) then it can run even in Safe
Mode.
You can also achieve the same thing with these two alternative commands, but it isn't as cool as
the above for loop
get-itemproperty "HKU:\*\Software\Microsoft\Windows\CurrentVersion\Run*" |
select -property * -exclude PSPR*,PSD*,PSC*,PSPAR* | fl
get-itemproperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run*" |
select -property * -exclude PSPR*,PSD*,PSC*,PSPAR* | fl
Removing Run evil
Be surgical here. You don't want to remove Run entries that are legitimate. It's important you
remove with -verbose too and double-check it has gone, to make sure you have removed what
you think you have.
#Then pick the EXACT name of the Run entry you want to remove. Copy paste it, includ
Remove-ItemProperty -Path "HKU:\SID-\Software\Microsoft\Windows\CurrentVersion\RunOn
Screensaver Persistence
It can be done, I swear. Mitre ATT&CK has instances of .SCR's being used to maintain regular
persistence
You can query the changes made in the last X days with this line
We can list all of the policies, and see where a policy contains a script or executable. You can
change the include at the end to whatever you want
Autoruns
Autoruns is a Sysinternals tool for Windows. It offers analysts a GUI method to examine the
recurring tasks that an adversary might use for persistence and other scheduled malice.
Before you go anywhere cowboy, make sure you've filtered out the known-goods under options.
It makes analysis a bit easier, as you're filtering out noise. Don't treat this as gospel though, so
yes hide the things that VirusTotal and Microsoft SAY are okay.....but go and verify that those
auto-running tasks ARE as legitimate as they suppose they are
I personally just stick to the 'Everything' folder, as I like to have full visibility rather than go into
the options one by one
Some things in autorun may immediately stick out to you as strange. Take for example the
malicious run key I inserted on the VM as an example:
You can right-click and ask Virus Total to see if the hash is a known-bad
And you can right-click and ask autoruns to delete this recurring task from existence
I like autoruns for digital forensics, where you take it one machine at a time. But - in my
uneducated opinion - it does not scale well. A tool like Velociraptor that allows orchestration
across thousands of machines can be leveraged to query things with greater granularity than
Autoruns allows.
This is why I like to use PowerShell for much of my blue team work on a Windows machine,
where possible. I can pre-filter my queries so I don't get distraced by noise, but moreover I can
run that fine-tuned PowerShell query network-wide across thosuands of machines and recieve
the results back rapidly.
File Queries
section contents
File tree
Fire off tree to list the directories and files underneath your current working directory, nestled
under each other
Let's say we want to look in all of the Users \temp\ directories. We don't want to put their names
in, so we wildcard it.
We also might only be interested in the pwsh scripts in their \temp, so let's filter for those only
We can also make this conditional. Let's say if Process MemeProcess is NOT running, we can
then else it to go and check if files exist
You can use test-path to query Registry, but even the 2007 Microsoft docs say that this can
give inconsistent results, so I wouldn't bother with test-path for reg stuff when it's during an IR
Get-item C:\Temp\Computers.csv |
select-object -property @{N='Owner';E={$_.GetAccessControl().Owner}}, *time, version
Change the variables in the first time to get what you're looking. Remove the third line if you
want to include directories
And then you can recursively remove the files and directories, in case malicious
Remove the last -whatif flag to actaully detonate. Will ask you one at a time if you want to delete
items. Please A to delete all
copy multiple files to new location
Grep in Powershell
Change the string in the second line. You should run these one after another, as it will grep for
things in unicode and then ascii.
I like to use these as really lazy low-key yara rules. So grep for the string "educational purposes
only" or something like that to catch malicious tooling - you'd be surprised how any vendors
take open-source stuff, re-brand and compile it, and then sell it to you.....
Registry Queries
section contents
A note on HKCU
Just a note: Anywhere you see a reg key does HKCU - this is Current User. Your results will be
limited to the user you are.
To see more results, you should change the above from HKCU, to HKU.
You often need the SID of the users you want to go and look at their information.
HKCU:\Control Panel\Desktop\
Becomes:
HKU\s-1-12-1-707864876-1224890504-1467553947-2593736053\Control Panel\Desktop
# show HK users
mount -PSProvider Registry -Name HKU -Root HKEY_USERS;(Gci -Path HKU:\).name
##lets take HKEY_CURRENT_USER as a subkey example. Let's see the entries in this sub
(Gci -Path HKCU:\).name
# If you want to absolutely fuck your life up, you can list the names recursively...
(Gci -Path HKCU:\ -recurse).name
HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
HKLM\SYSTEM\MountedDevices
Query the services on this machine, and if you want to see more about one of the results just
add it to the path
HKLM\SYSTEM\CurrentControlSet\Services
HKLM\SYSTEM\CurrentControlSet\Services\ACPI
HKLM\Software
HKLM\Software\PickOne
Query SIDs
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\[Long-SID-
Number-HERE]
Query user's wallpaper. Once we know a user’s SID, we can go and look at these things:
HKU\S-1-5-18\Control Panel\Desktop\
# Read the reg to make sure this is the bad boy you want
get-itemproperty -Path 'HKU:\*\Keyboard Layout\Preload\'
#remove it by piping it to remove-item
get-itemproperty -Path 'HKU:\*\Keyboard Layout\Preload\' | Remove-Item -Force -Confi
# double check it's gone by trying to re-read it
get-itemproperty -Path 'HKU:\*\Keyboard Layout\Preload\'
Removing HKCurrentUser Keys
If a Registry is under HKCU , it's not clear exactly WHO it can belong to.
If a Registry is under HKCU , you can figure out WHICH username it belongs to but you can't just
go into HKCU in your PwSh to delete it....because YOU are the current user.
And then you can traverse to that as the path as HKU. So for example, under User_Alfonso's reg
keys
#this
HKCU:\Software\AppDataLow\Software\Microsoft\FDBC3F8C-385A-37D8-2A81-EC5BFE45E0BF
#must become this. Notice the reg changes in the field field, and the SID gets sandw
HKU:\S-1-5-21-912369493-653634481-1866108234-1004\Software\AppDataLow\Software\Micro
Adversaries will look for registries with loose permissions, so let's show how we first can identify
loose permissions
Get-ACl
The Access Control List (ACL) considers the permissions associated with an object on a
Windows machine. It's how the machine understands privileges, and who is allowed to do what.
Problem is, if you get and get-acl for a particular object, it ain't a pretty thing
There's a lot going on here. Moreover, what the fuck is that SDDL string at the bottom?
The Security Descriptor Definition Language (SDDL) is a representation for ACL permissions,
essentially
Convert SDDL
You could figure out what the wacky ASCII chunks mean in SDDL....but I'd much rather convert
the permissions to something human readable
Here, an adversary is looking for a user they control to have permissions to maniptulate the
service, likely they want Full Control
An adversary in control of a loosely permissioned registry entry for a service, for example, could
give themselves a privesc or persistence. For example:
The below takes the services reg as an example, and searches for specifically just the reg-key
Name and Image Path.
#You can search recursively with this, kind of, if you use wildcards in the path nam
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\**\*" |
ft PSChildName, ImagePath -autosize | out-string -width 800
Remember in the above example of a malicious reg, we saw the ImagePath had the value of
C:\temp\evil.exe. And we're seeing a load of .sys here. So can we specifically just filter for .exes
in the ImagePath.
I have to mention, don't write .sys files off as harmless. Rootkits and bootkits weaponise .sys, for
example.
If you see a suspicious file in reg, you can go and collect it and investigate it, or collect it's hash.
When it comes to the ImagePath, \SystemRoot\ is usually C:\Windows, but you can confirm with
$Env:systemroot .
# We can filter however we wish, so we can actively NOT look for .exes
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\services\*" |
where ImagePath -notlike "*.exe*" |
ft PSChildName, ImagePath -autosize | out-string -width 800
#fuck it, double stack your filters to not look for an exe or a sys...not sure why,
Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\services\*" |
? {($_.ImagePath -notlike "*.exe*" -and $_.Imagepath -notlike "*.sys*")} |
ft PSChildName, ImagePath -autosize | out-string -width 800
#If you don't care about Reg Entry name, and just want the ImagePath
(Get-ItemProperty -Path "HKLM:\System\CurrentControlSet\services\*").ImagePath
OR BAMParser.ps1
Driver Queries
section contents
Drivers are an interesting one. It isn't everyday you'll see malware sliding a malicious driver in ;
bootkits and rootkits have been known to weaponise drivers. But it's well worth it, because it's
an excellent method for persistence if an adversary can pull it off without blue-screening a
machine. You can read more about it here
You can utilise Winbindex to investigate drivers, and compare a local copy you have with the
indexed info. Malicious copies may have a hash that doesn't match, or a file size that doesn't
quite match.
Printer Drivers
System Drivers
If drivers are or aren't signed, don't use that as the differentiation for what is legit and not legit.
Some legitimate drivers are not signed ; some malicious drivers sneak a signature.
Unsigned
Get unsigned drivers. Likely to not return much
Signed
Get-WmiObject Win32_PnPSignedDriver |
fl DeviceName, FriendlyName, DriverProviderName, Manufacturer, InfName, IsSigned, Dr
# alternatives
gci -path C:\Windows\System32\drivers -include *.sys -recurse -ea SilentlyContinue |
Get-AuthenticodeSignature |
? Status -eq "Valid" | ft -autosize
#or
gci C:\Windows\*\DriverStore\FileRepository\ -recurse -include *.inf|
Get-AuthenticodeSignature |
? Status -eq "Valid" | ft -autosize
Other Drivers
Gets all 3rd party drivers
Drivers by Registry
You can also leverage the Registry to look at drivers
#if you know the driver, you can just give the full path and wildcard the end if you
get-itemproperty -path "HKLM:\System\CurrentControlSet\Services\DBUtil*"
#You'll likely not know the path though, so just filter for drivers that have \drive
get-itemproperty -path "HKLM:\System\CurrentControlSet\Services\*" |
? ImagePath -like "*drivers*" |
fl ImagePath, DisplayName
(
Drivers by Time
Look for the drivers that exist via directory diving.. We can focus on .INF and .SYS files, and sort
by the time last written.
section contents
But what about getting granular. Well, let's pick on a specific process we can see running, and
let's get the DLLs involved, their file location, their size, and if they have a company name
Generically
This will return a lot of DLLs and their last write time. I personally would avoid this approach
Like drivers, if a DLL is signed or un-signed, it doesn't immediately signal malicious. There are
plenty of official files on a Windows machine that are unsigned. Equally, malicious actors can get
signatures for their malicious files too.
You'll get a lot of results if you look for VALID, signed DLLs. So maybe filter for INVALID ones
first. Both will take some time
#get invalid
gci -path C:\Windows\*, C:\Windows\System32\* -file -force -include *.dll |
Get-AuthenticodeSignature | ? Status -ne "Valid"
Specifically
We can apply all of the above to individual DLLs. If I notice something strange during the
process' DLL hunt, or if I had identified a DLL with an invalid signature. I'd then hone in on that
specific DLL.
If you need to verify what a DLL is, you have a myriad of ways. One way is through Winbindex
Here, you can put the name of a DLL (or many of other filetypes), and in return get a whole
SLUETH of data. You can compare the file you have locally with the Winbindex info, which may
highlight malice - for example, does the hash match ? Or, is your local copy a much larger file
size than the suggested size in the index?
If not Windex, you have the usual Google-Fu methods, and having the file hash will aid you here
AV Queries
section contents
Query Defender
If you have Defender active on your windows machine, you can leverage PowerShell to query
what threats the AV is facing
This simple command will return all of the threats. In the screenshot below, it shows someone
attempted to download mimikatz.
Get-MpThreatDetection
However, if you have numerous threat alerts, the above command may be messy to query. Let's
demonstrate some augmentations we can add to make our hunt easier
Update-MpSignature; Start-MpScan
#Specify path
Start-MpScan -ScanPath "C:\temp"
Get-MpComputerStatus | fl *enable*
Adversaries also enjoy adding exclusions to AVs....however please note that some legitimate
tooling and vendors ask that some directories and executables are placed on the exclusion list
Get-MpPreference | fl *Exclu*
If you see some values have been disabled, you can re-enable with the following:
Log Queries
section contents
From a security perspective, you probably don't want to query logs on the endpoint
itself....endpoints after a malicious event can't be trusted. You're better to focus on the logs that
have been forwarded from endpoints and centralised in your SIEM.
If you REALLY want to query local logs for security-related instances, I can recommend this
awesome repo
I've tended to use these commands to troubleshoot Windows Event Forwarding and other log
related stuff.
Show Logs
Show logs that are actually enabled and whose contents isn't empty.
Get-WinEvent -ListLog *|
where-object {$_.IsEnabled -eq "True" -and $_.RecordCount -gt "0"} |
sort-object -property LogName |
format-table LogName -autosize -wrap
Checks if the date was written recently, and if so, just print sysmon working if not recent, then
print the date last written. I've found sometimes that sometimes sysmon bugs out on a machine,
and stops committing to logs. Change the number after -ge to be more flexible than the one
day it currently compares to
Nonetheless, you can read the EVTX file you are interesting in
netsh http show urlacl url=http://+:5985/wsman/ && netsh http show urlacl url=https:
Usage Log
These two blogs more or less share how to possibly prove when a C#/.net binary was executed
1, 2
The log's contents itself is useless. But, the file name of the log may be telling as it will be
named after the binary executed.
# Show usage log but split to focus on the username, executable, and machine name in
(gci "C:\Users\*\AppData\Local\Microsoft\*\UsageLogs\*").fullname |
ForEach-Object{$data = $_.split("\\");write-output "$($data[8]), $($data[2]), $(host
Select-String -notmatch "powershell", "NGenTask","sdiagnhost"
Powershell Tips
section contents
Get Alias
PwSh is great at abbreviating the commands. Unfortunately, when you're trying to read someone
else's abbreviated PwSh it can be ballache to figure out exactly what each weird abbrevation
does.
Equally, if you're trying to write something smol and cute you'll want to use abbrevations!
Whatever you're trying, you can use Get-Alias to figure all of it out
Try to give singulars, not plural. For example, instead of drivers just do driver
get-command *driver*
## Once you see a particular command or function, to know what THAT does use get-hel
# get-help [thing]
Get-Help Get-SystemDriver
WhatIf
-WhatIf is quite a cool flag, as it will tell you what will happen if you run a command. So before
you kill a vital process for example, if you include whatif you'll gain some insight into the
irreversible future!
Clip
You can pipe straight to your clipboard. Then all you have to do is paste
# use the -expandproperty before the object you want. IN this case, ID
select -ExpandProperty id
# so for example
get-process -Name "google*" | select -ExpandProperty id
# lets stop the particular google ID that we want
$PID = get-process -Name "google" | ? Path -eq $Null | select -ExpandProperty id;
Stop-Process -ID $PID -Force -Confirm:$false -verbose
If you pipe to | format-table you can simply use the -HideTableHeaders flag
Re-run commands
If you had a command that was great, you can re-run it again from your powershell history!
Stop Trunction
Out-String
For reasons(?) powershell truncates stuff, even when it's really unhelpful and pointless for it to
do so. Take the below for example: our hash AND path is cut off....WHY?! :rage:
To fix this, use out-string
#put this at the very end of whatever you're running and is getting truncated
| outstring -width 250
# or even more
| outstring -width 4096
#use whatever width number appropiate to print your results without truncation
Look no elipses!
-Wrap
In some places, it doesn't make sense to use out-string as it prints strangely. In these instances,
try the -wrap function of format-table
This, for example is a mess because we used out-string. It's wrapping the final line in an
annoying and strange way. ans
| ft -property * -autosize -wrap
#you don't always need to the -property * bit. But if you find it isn't printing as
| ft -autosize -wrap
Directories
For some investigations, I need to organise my directories or everything will get messed up. I
enjoy using Year-Month-Date in my directory names!
##save outputs to
echo 'test' > C:\Malware_Analysis\$(Get-Date -UFormat "%Y_%b_%d_%a_UTC%Z")\test.txt
Transcripts
Trying to report back what you ran, when you ran, and the results of your commands can
become a chore. If you forget a pivotal screenshot, you'll kick yourself - I know I have.
Instead, we can ask PowerShell to create a log of everything we run and see on the command
line.
# you can pick whatever path you want, this is just what I tend to use it for
Start-Transcript -path "C:\Malware_Analysis\$(Get-Date -UFormat "%Y_%b_%d_%a_UTC%Z
## At the end of the malware analysis, we will then need to stop all transcripts
Stop-transcript
#you can now open up your Powershell transcript with notepad if you want
Linux
This section is a bit dry, forgive me. My Bash DFIR tends to be a lot more spontaneous and
therefore I don't write them down as much as I do the Pwsh one-liners
Bash History
section contents
Checkout the SANS DFIR talk by Half Pomeraz called You don't know jack about .bash_history.
It's a terrifying insight into how weak bash history really is by default
Via .bashrc
nano ~/.bashrc
#at the bottom
export HISTTIMEFORMAT='%d/%m/%y %T '
#expand bash history size too
nano /etc/profile
export HISTTIMEFORMAT='%d/%m/%y %T '
Then run the history command to see your timestamped bash history
grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][
IPv6
egrep '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA
Stack up IPv4s
Great for parsing 4625s and 4624s in Windows world, and seeing the prelevence of the IPs
trying to brute force you. Did a thread on this
So for example, this is a txt of all 4654s for an external pereimter server
grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][
To then prepare this to compare to the 4624s, I find it easiest to use this [cyberchef recipe]
(https://gchq.github.io/CyberChef/#recipe=Extract_IP_addresses(true,false,false,false,false,false
)Sort('Line%20feed',false,'Alphabetical%20(case%20sensitive)')Unique('Line%20feed',false)Fin
d_/_Replace(%7B'option':'Regex','string':'%5C%5Cn'%7D,'%7C',true,false,true,false))
And now, compare the brute forcing IPs with your 4624 successful logins, to see if any have
successfully compromised you
Ack is like Grep's younger, more refined brother. Has some of greps' flags as default, and just
makes life a bit easier.
ps -aux --forest
sudo ls -l /proc/[0-9]*/exe 2>/dev/null | awk '/ -> / {print $NF}' | sort | tac
Get a quick overview of network activity
netstat -plunt
#if you don't have netstat, try ss
ss -plunt
This alternative also helps re-visualise the originating command and user that a network
connection belongs to
sudo lsof -i
Files
section contents
Recursively look for particular file types, and once you find the files get their
hashes
Here's the bash alternative
find . type f -exec sha256sum {} \; 2> /dev/null | grep -Ei '.asp|.js' | sort
Tree
Tree is an amazing command. Please bask in its glory. It will recursively list out folders and
filders in their parent-child relationship.....or tree-branch relationship I suppose?
Tree and show the users who own the files and directories
tree -u
#stack this with a grep to find a particular user you're looking for
tree -u | grep 'root'
If you find it a bit long and confusing to track which file belongs to what directory, this flag on
tree will print the fullpath
tree -F
# pipe with | grep 'reports' to highlight a directory or file you are looking for
Get information about a file
stat is a great command to get lots of information about a file
stat file.txt
This one will print the files and their corresponding timestamp
I've got to be honest with you, this is one of my favourite commands. The level of granularity you
can get is crazy. You can find files that have changed state by the MINUTE if you really wanted.
find -newerct "01 Jun 2021 18:30:00" ! -newerct "03 Jun 2021 19:00:00" -ls | sort
Compare Files
vimdiff is my favourite way to compare two files
diff is the lamer, tamer version of vimdiff . However it does have some flags for quick
analysis:
Fixing Mistakes
We all make mistakes, don't worry. Bash forgives you
We've all done it mate. Luckily, !! has your back. The exclamation mark is a history related
bash thing.
Using two exclamations, we can return our previous command. By prefixing sudo we are
bringing our command back but running it as sudo
#for testing, fuck up a command that needed sudo but you forgot
cat /etc/shadow
# fix it!
sudo !!
The fc command is interesting. It gets what was just run in terminal, and puts it in a text editor
environment. You can the ammend whatever mistakes you may have made. Then if you save and
exit, it will execute your newly ammended command
##messed up command
cat /etc/prozile
#fix it
fc
#then save and exit
If you had a beautiful command you ran ages ago, but can't remember it, you can utilise
history . But don't copy and paste like a chump.
Instead, utilise exclamation marks and the corresponding number entry for your command in the
history file. This is highlighted in red below
Correct way to just read a plist is plutil -p but there are multiple different methods so do
whatever, I’m not the plist police
If the plist is in binary format, you can convert it to a more readable xml: plutil -convert xml1
<path_to_binary_plist>
Quarantine Events
Files downloaded from the internet
The db you want to retrieve will be located here with a corresponding username:
/Users/*/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2
Here’s a dope one-liner that organises the application that did the downloading, the link to
download, and then the date it was downloaded, via sqlite
sqlite3 /Users/dray/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2
'select LSQuarantineAgentName, LSQuarantineDataURLString, date(LSQuarantineTimeStamp
| sort -u | grep '|' --color
Install History
Find installed applications and the time they were installed from :
/Library/Receipts/InstallHistory.plist
Annoyingly doesn’t show corresponding user ? However, it does auto sort the list by datetime
which is helpful
plutil -p /Library/Receipts/InstallHistory.plist
Location Tracking
Some malware can do creeper stuff and leverage location tracking Things you see here offer an
insight into the programs and services allowed to leverage location stuff on mac
#plain read
sudo plutil -p /var/db/locationd/clients.plist
/Users/*/Library/Application Support/com.apple.sharedfilelist/
#full path to this stuff
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/*/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFile
/Users/users/Library/Application Support/com.apple.sharedfilelist/com.apple.LSShared
There are legitimate ways to parse whats going on here……but that just ain’t me chief - I strings
these bad boys
Audit Logs
praudit command line tool will let you read the audit logs in /private/var/audit/
Examples
What was the user dray up to on 13th May 2022: auditreduce -d 20220513 -u dray
/var/audit/* | praudit
What happened between two dates: auditreduce /var/audit/* -a 20220401 -b 20220501 | praudit
plutil -p /private/var/db/dslocal/nodes/Default/groups/admin.plist
Persistence locations
Not complete, just some easy low hanging fruit to check.
# scripts
/Users/*/Library/Preferences/com.apple.loginwindow.plist
/etc/periodic/[daily, weekly, monthly]
The TCC db (Transparency, Consent, and Control) offers insight when some applications have
made system changes. There are at least two TCC databases on the system - one per user, and
one root.
/Library/Application Support/com.apple.TCC/TCC.db
/Users/*/Library/Application Support/com.apple.TCC/TCC.db
You can use sqlite3 to parse, but there are values that are not translated and so don’t make too
much sense
You can use some command line tools, or just leverage a tool like Velociraptor, use the dedicated
TCC hunt, and point it at the tcc.db you retrieved.
One of the most beneficial pieces of information is knowing which applicaitons have FDA (Full
Disk Access), via the kTCCServiceSystemPolicyAllFiles service. This is only located in the
root TCC database.
Built-In Security Mechanisms
There are some built-in security tools on macOS that can be queried with easy command line
commands. This will get the status of the following.
# Airdrop
sudo ifconfig awdl0 | awk '/status/{print $2}'
# Filevault
sudo fdesetup status
# Firewall
defaults read /Library/Preferences/com.apple.alf globalstate // (Enabled = 1, Disab
# Gatekeeper
spctl --status
# Network Fileshare
nfsd status
# Remote Login
sudo systemsetup -getremotelogin
# Screen sharing
sudo launchctl list com.apple.screensharing
# SIP
csrutil status
Malware
section contents
I'd reccomend REMnux, a Linux distro dedicated to malware analysis. If you don't fancy
downloading the VM, then maybe just keep an eye on the Docs as they have some great
malware analysis tools in their roster.
I'd also reccomend FlareVM, a Windows-based malware analysis installer - takes about an hour
and a half to install everything on on a Windows VM, but well worth it!
section contents
Thor
Florian Roth's Thor requires you to agree to a licence before it can be used.
There are versions of Thor, but we'll be using the free, lite version
What I'd reccomend you do here is create a dedicated directory ( /malware/folder ), and put
one file in at a time into this directory that you want to study.
#execute Thor
./thor-lite-macosx -a FileScan \
-p /Malware/folder:NOWALK -e /malware/folder \
--nothordb --allreasons --utc --intense --nocsv --silent --brd
Capa
Capa is a great tool to quickly examine wtf a binary does. This tool is great, it previously helped
me identify a keylogger that was pretending to be an update.exe for a program
Usage
The command file is likely to be installed in most unix, MacOS, and linux OS'. Deploy it next to
the file you want to interrograte
exiftool may have to be installed on your respective OS, but is deplopyed similarly be firing it
off next to the file you want to know more about
Strings
Honestly, when you're pressed for time don't knock strings . It's helped me out when I'm
under pressure and don't have time to go and disassemble a compiled binary.
Strings is great as it can sometimes reveal what a binary is doing and give you a hint what to
expect - for example, it may include a hardcoded malicious IP.
Floss
Ah you've tried strings . But have you tried floss? It's like strings, but deobfuscate strings in a
binary as it goes
#execute
floss -n3 '.\nddwmkgs - Copy.dll'
Flarestrings
Flarestrings takes floss and strings, but adds a machnine learning element. It sorts the strings
and assigns them a 1 to 10 value according to how malicious the strings may be.
flarestrings.exe '.\nddwmkgs - Copy.dll' |
rank_strings -s # 2>$null redirect the erros if they get in your way
Win32APIs
Many of the strings that are recovered from malware will reference Win32 APIs - specific
functions that can be called on when writing code to interact with the OS in specific ways.
To best understand what exactly the Win32 API strings are that you extract, I'd suggest Malapi.
This awesome project maps and catalogues Windows APIs, putting them in a taxonomy of what
they generally do
Regshot
regshot.exe is great for malware analysis by comparing changes to your registry.
If your language settings have non-Latin characters (e.g. Russian, Korean, or Chinese), use
unicode release
#pull it
wget -usebasicparsing https://github.com/Seabreg/Regshot/raw/master/Regshot-x64-ANSI
.\regshot.exe
#run the GUI for the first 'clean' reg copy. Takes about a minute and a half
Lee Holmes dropped some serious PowerShell knowledge in this Twitter exchange 1, 2. This
takes longer than Regshot, but if you wanted to stick to PwSh and not use tooling you can.
#Base snapshot
gci -recurse -ea ignore -path HKCU:\,HKLM:\ | % {[PSCustomObject] @{Name = $_.Name;
## Execute malware
#New shapshot
gci -recurse -ea ignore -path HKCU:\,HKLM:\ | % {[PSCustomObject] @{Name = $_.Name;
#Compare
diff (gc .\test.txt) (gc .\test2.txt) -Property Name,Value
Fakenet
Use fakenet in an Windows machine that doesn't have a network adapter. Fakenet will emulate a
network and catch the network connections malware will try to make.
The linux command ent is useful here. binwalk -E is a posssible alternative, however I have
found it less than reliable
The screenshot belows shows a partially encrytped file in the first line, and then a plain text txt
file in the second line.
#download script
#start powersiem.ps1
C:\users\*\Desktop\SysmonLab\PowerSiem.ps1
#detonate malware
Unquarantine Malware
Many security solutions have isolation techniques that encrypt malware to stop it executing.
ProcMon is a great tool to figure out what a potentially malicious binary is doing on an endpoint.
There are plenty of alternatives to monitor the child processes that a parent spawns, like any.run.
But I'd like to focus on the free tools to be honest.
Keylogger Example
Let's go through a small investigation together, focusing on a real life keylogger found in an
incident
When I get started with ProcMon, I have a bit of a habit. I stop capture, clear the hits, and then
begin capture again. The screenshot details this as steps 1, 2, and 3.
I then like to go to filter by process tree, and see what processes are running
Process tree
When we look at the process tree, we can see something called Keylogger.exe is running!
Right-click, and add the parent-child processes to the filter, so we can investigate what's going
on
Honing in on a child-process
And if we go to that particular file, we can see the keylogger was outputting our keystrokes to
the policy.vpol file
That's that then, ProcMon helped us figure out what a suspicious binary was up to!
section contents
Word of Warning
Changing the hash of a file is easily done. So don't rely on this method. You could very well
check the hash on virus total and it says 'not malicious', when in fact it is recently compiled by
the adversary and therefore the hash is not a known-bad
And BTW, do your best NOT to upload the binary to VT or the like, the straight away. Adversaries
wait to see if their malware is uploaded to such blue team websites, as it gives them an
indication they have been burned. This isn't to say DON'T ever share the malware. Of course
share with the community....but wait unitl you have stopped their campaign in your environment
get-filehash file.txt
# optionally pipe to |fl or | ft
In Linux
sha256sum file.txt
Virus Total
One option is to compare the hash on Virus Total
Sometimes it's scary how many vendors' products don't show flag malware as malicious....
The details tab can often be enlightening too
Malware Bazaar
Malware Bazaar is a great alternative. It has more stuff than VT, but is a bit more difficult to use
You'll need to prefix what you are searching with on Malware Bazaar. So, in our instance we have
a sha256 hash and need to explicitly search that.
Notice how much Malware Bazaar offers. You can go and get malware samples from here and
download it yourself.
Sometimes, Malware Bazaar offers insight into the malware is delivered too
Winbindex
Winbindex is awesome. The info behind the site can be read here. But in essence, it's a repo of
official Windows binaries and their hashes.
We've already discussed it about Drivers and DLLs, so I won't go into too much detail. This won't
give you an insight into malware, but it will return what the details of an official binary should be.
This is powerfull, as it allows us to know what known-goods should look like and have.
If we click on Extras we get insightful information about the legitimate filepath of a file, its
timestamp, and more!
Decoding Powershell
section contents
Hex
if when you decode it's still giberish but you see it involves bytes, save the gibberish output as
*.dat
And then leverage scdbg for 32 bit and speakeasy for 64 bit
scdgb /find malice.dat /findsc # looks for shelcode and if that fails go down to....
speakeasy -t malice.dat -r -a x64
reflection assembly
xor xcrypt
you can xor brute force in cyberchef, change the sample lentgh to 200.
A lof of PowerShell malware that uses XOR will include the decimal somewhere in the script. Use
cyberchef's XOR and feed in that decimal.
unzippping
When something detects from base64 as Gzip, undo the Gzip filter and use the raw inflate
instead.
tidying up
To tidy up you can change stupid CAmeLcaSE to lower case
And then in find and replace, replace semi-colon with ;\n\n to create space
Example String
Through experience, we can eventually keep two things in mind about decoding powershell: the
first is that it's from base64 ; the second is that the text is a very specific UTF (16 little endian). If
we keep these two things in mind, we're off to a good start.
We can then input those options in Cyberchef . The order we stack these are important!
https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-
9%2B/%3D',true)Decode_text('UTF-16LE%20(1200)')
Decoding
In theory, now we have set up cyberchef it should be as easy as just copying the encoded line in
right?
Well. Nearly. For reasons (?) we get chinese looking characters. This is because we have
included plaintext human-readable in this, so the various CyberChef options get confused.
Obfuscation
I had an instance where 'fileless malware' appeared on a user's endpoint. Whilst I won't take us
all the way through that investigation, I'll focus on how we can unobfuscate the malware.
Reversing Malware
Using cyberchef
Example string
But keep in mind, to make this work we need to remove human-readable text....if we do this, we
may lose track of what powershell the malware is actually deploying. So it's a good idea to make
extensive notes.
We get some interestng stuff here. First, we can see it goes to base64 AGAIN; second, we can
see that gzip is being brought into the game
Magic
But let's pretend we didn't see the Gzip part of the script. Is there a way we can 'guess' what
methods obfscuation takes?
Absolutely, the option is called Magic in CyberChef. It's a kind of brute forcer for detecting
encoding, and then offering a snippet of what the text would look like decoded.
So take the base64 text from the script, and re-enter it by itself
We can turn the UTF option off now, and turn magic on. I tend to give it a higher intensive
number, as it's all client-side resource use so it's as strong as your machine is!
Well looky here, we can see some human-readable text. So now we know to stack add gzip to
our decoding stack in cyberchef. From Magic, just click the link of the particular decoding option
it offers
Gzip and Xor
We're starting to get somewhere with this script! But we're gonna need to do some more
decoding unfortunately.
There's something sneaky about this malware. It's using some encyrption....but we can break it
with XOR
If we trial and error with the numbers and decimals, we can eventually start the cracking process
Defang
CyberChef has taken us as far as we can go. To find out what happens next, we need to run this
on a test rig. But we need to de-fang all of the dangerous bits of this script.
John Hammond, a security researcher and awesome youtuber, introduced me to the concept of
replacing variables in malicious scripts. If you replace-all for the variable, you can introduce
variables that are familiar.
#original variable
$s==New-Object IO.MemoryStream(,[Convert]::FromBase64String("H4sIAA......
#changed
$bse64=New-Object IO.Me
It isn't much, but in a big long complicated script, changing variables helps keep track of what's
going on.
After this, we need to make sure that running this script won't actually execute anything
malicious on our system. We just want to see what it will do.
Remove IEX where you see it. Don't get rid of the brackets though.
Once you've de-fanged the script, you are alright to run it and will just print the output to the
screen:
A Layer Deeper
So CyberChef got us here, and we were limited there. So now let's de-fang this resulting script
and see where they takes us
If we scroll around, we can see see some of the logic of the script. At the bottom, we see that it
will execute the output of a variable as a Job, which we've touched on before
Let's remove the IEX at the bottom, and neutralise the job by commenting it out
....to be continued!!!
Bytes
Here's a seperate bit of Powershell malware. I decoded it up to a point, and I want to focus on
some easy ways to decode BYTES.
If ([IntPtr]::size -eq 8) {
[Byte[]]$var_code = [System.Convert]::FromBase64String('32ugx9PL6yMjI2JyYnNxcnVrEv
If we `echo $malware" we can see we get some numbers. These are likely bytes.
We can push these bytes straight into an .exe
[System.IO.File]::WriteAllBytes(".\evil.exe", $malware)
Then we can string the evil.exe, and we can see that it includes a bad IP, confirming this was
indeed malware!
SOC
Sigma Converter
The TL;DR of Sigma is that it's awesome. I won't go into detail on what Sigma is, but I will tell you
about an awesome tool that lets you convert sigma rules into whatever syntax your SOC uses:
Uncoder
You can convert ONE standard Sigma rule into a range of other search syntax languages
automatically
SOC Prime is a market place of Sigma rules for the latest and greatest exploits and
vulnerabilities
You can pick a rule here, and convert it there and then for the search langauge you use in your
SOC
Honeypots
One must subscribe to the philosophy that compromise is inevitable. And it is. As Blue Teamers,
our job is to steel ourselves and be ready for the adversary in our network.
Honeypots are advanced defensive security techniques. Much like a venus flytrap that seeks to
ensnare insects, a honeytrap seeks to ensare the adversary in our network. The task of the
honeypot is to allure the adversary and convince them to interact. In the mean time, our
honeypot will alert us and afford us time to contain and refute the adversary - all the while, they
were pwning a honeypot they believed to be real but in fact did not lasting damage.
Look, there isn't anything I could teach you about honeypots that Chris Sanders couldn't teach
you better. Everything you and I are gonna talk about in the Blue Team Notes to do with
Honeypots, Chris Sanders could tell you and tell you far better. But for now, you're stuck with
me!
section contents
Basic Honeypots
An adversaries' eyes will light up at an exposed SSH or RDP. Perhaps it's not worth your time
having an externally-facing honeypot (adversaries all over the world will brute force and try their
luck). But in your internal network, emulating a remote connection on a juicy server may just do
the trick to get the adversary to test their luck, and in doing so notify you when they interact with
the honeypot
Telnet Honeypot
WHOMST amongst us is using telnet in the year of our LORDT 2021?!.....a shocking number
unfortunately....so let's give a honeypot telnet a go!
On a linux machine, set this fake telnet up with netcat. Also have it output to a log, so you are
able to record adversaries' attempts to exploit.
You can check in on this log, or have a cronjob set up to check it's contents and forward it to you
where necessary
#test it works!
#an attacker will then use to connect and run commands
telnet 127.0.0.1
whoami
#netcat willl show what the attacker ran.
If you run this bad boy, you can see that the .LOG captures what we run when we telnet in. The
only downside of this all of course is we do not have a real telnet session, and therefore it will not
speak back to the adversary nor will it keep them ensnared.
HTTP Honeypot
Our fake web server here will ensnare an adversary for longer than our telnet. We would like to
present the webserver as an 'error' which may encourage the adversary to sink time into making
it 'not error'.
In the mean time, we can be alerted, respond, gather information like their user agent,
techniques, IP address, and feed this back into our SOC to be alerted for in the future.
First, you will need a index.html file. Any will do, I'll be borrowing this one
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>We've got some trouble | 403 - Access Denied</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necol
</head>
<body>
<div class="cover"><h1>Access Denied <small>403</small></h1><p class="lead">The
<footer><p>Technical Contact: <a href="mailto:[email protected]">larry@honeypot
</body>
</html>
Second, we now need to set up our weaponised honeypot. Here's a bash script to help us out:
#!/bin/bash
#variables
PORT=80
LOG=hpot.log
#data to display to an attcker
BANNER=`cat index.html` # notice these are ` and not '. The command will run incorre
# create a temp lock file, to ensure only one instance of the HP is running
touch /tmp/hpot.hld
echo "" >> $LOG
#while loop starts and keeps the HP running.
while [ -f /tmp/hpot.hld ]
do
echo "$BANNER" | ncat -lvnp $PORT 1>> $LOG 2>> $LOG
# this section logs for your benefit
echo "==ATTEMPTED CONNECTION TO PORT $PORT AT `date`==" >> $LOG # the humble `date
echo "" >> $LOG
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" >> $LOG # seperates
done
Test this locally by examining 127.0.0.1 in your browser, your .LOG file should have a FIT over this
access and record much of your attempts to do something naughty, like brute forcing ;)
Why don't we backdoor some naighty commands that adversaries like to use on 'Nix machines.
Off the top of my head, we can boobytrap nano , base64 , wget and curl , but you'll think of
something more imaginative and clever, I am sure.
#IRL
alias wget ='curl http://honey.comands.uk/$(hostname -f) > /dev/null 2>&1 ; wget'
# Hostname -f will put the fully qualified domain name of the machine into the GET r
#ideally, the website you first hit be a cloud instance or something. Don't actual
# the reason we ask it to curl the machine name directory is to alert OUR listen
#for testing
# I am hardcoding the machine name in the directory as an example. If I were you,
alias wget='curl http:/127.0.0.1/workstation1337 > /dev/null 2>&1 ; wget'
If we have a listening web server in real life, it will snitch on the adversary trying to use WGET.
This is true for any of the other commands we do too
Network Traffic
I'll be honest with you. Network traffic is where it's at. Endpoints and their logs are fallible, they
can be made to LIE to you by an adversary. But packets? Packet's don't lie.
There's a great SANS talk and corresponding paper, called Packets or it Didn't Happen, all about
the utility of network traffic's advantadges over endpoint log monitoring.
section contents
Capture Traffic
section contents
When we're talking about capturing traffic here, we really mean capturing traffic in the form of
packets.
But it's worth taking a smol digression to note what implementing continuous monitoring of
traffic means in your environment
To capture continuous traffic, as well as to capture it in different formats like Netflow &
metadata, you will need to install physical sensors, TAPS, and the like upstream around your
network. You will also need to leverage DNS server traffic, internal firewall traffic, and activity
from routers/switches especialy to overcome VLAN segregation.
North to South monitoring = monitoring ingress and egress traffic = stuff that's coming in
external to your domain and stuff that's leaving your domain out to the big bad internet
East to West monitoring = monitoring communication between machines in the Local Area
Network = stuff that your computers talking about with one another.
I really encourage you to read and watch the SANS stuff on this topic.
Packet Versions
Listen buddy, I'll have you know we base things on SCIENCE around here. And the SCIENCE says
that not all packet capture file types are born equal.
Pcapng or Pcap
According to a SANS research paper on the matter, pcapng is the superior packet we should
strive for compared to pcap
PCAP Next Generation (PCAPng) has some advantadges over it's predecessor, PCAP. It's explicit
goal is to IMPROVE on pcap
Unfortunately, Pcapng isn't popular. Not many tools can output a pcacpng file or use it as
default. Most tools can read it just fine though, so that's a big plus. Fortunately for you and I,
Wireshark and Tshark use Pcapng as their default output for captured packets and therefore we
can still leverage this New Generation.
If you want to write in pcapng, you can read about it (here)[#I-want-pcapng] in the Blue Team
Notes
ETL
According to the docs, ETLs (or Event Trace Logs) are based on the ETW framework (Event
Tracing for Windows). ETW captures a number of things, and when we leverage network
monitoring in windows we are simply leveraging one of the many things ETW recognises and
records in ETL format.
We don't need to over complicate it, but essentially .ETLs are records of network activity taken
from the ETW kernel-level monitor.
It is possible to convert .ETL captured network traffic over to .Pcap, which we talk about here in
the Blue Team Notes
Capture on Windows
Preamble
Weird one to start with right? But it isn't self evident HOW one captures traffic on Windows
You COULD download Wireshark for Windows, or WinDump, or Npcap. If you want to download
anything on a Windows machine, it's a tossup between Wireshark and Microsoft's Network
Monitor
Netsh Trace
But to be honest, who wants to download external stuff??? And who needs to, when you can
leverage cmdline's netsh
:: run as admin
netsh trace start capture=yes maxSize=0 filemode=single tracefile=C:\captured_traffi
:: to stop
netsh trace stop
:: will take a while now!
The astute will have noted that files that end in .ETL are not .PCAP. For reasons I don't know,
Microsoft decided to just not save things as Pcap? I don't know man.
:: example usage
etl2pcapng.exe original.etl converted.pcapng
Preperation
Tcpdump can listen to a LOT....too much actually. So we need to help it out by offering a
particular network interface. To see all of the interface options we can give to tcpdump, you can
use the following command which will uniquely look at your local system and throw up the
options
#list interfaces
tcpdump -D
Perchance you only want to capture particular traffic from particular Protocols Ports, and IPs. It's
surprisingly easy to do this
#or
tcpdump -i x host 10.10.10.99
Outputting
tcpdump -i x -w traffic.pcap
You can now take that over to the TShark section of the Blue Team Notes for some SERIOUS
analysis.
I want PCAPNG
In TShark, pcapng is the default file format. TShark shared many of the same flags as tcpdump,
so we don't need to go over that in too much detail.
Say you turn around, look me dead in the eye and say "PCAP analysis here, now, fuck TShark". It
is possible to do some interesting things with live packet inspection as the packets come in.
First, we'll need to attach the --immediate-mode flag for these all. Usually, tcpdump buffers the
writing of packets so as not to punish the OS' resource. But seeing as we're printing live and not
saving the packets, this does not concern us.
We can print the ASCII translation of the info in the packets. In the screenshot below, you can
see the first half is run without ASCII and the second is run with ASCII. Comes out messy, but
may prove useful one day?
You can also print helpful things live like different time formats as well as packet numbers
#packet numbers
sudo tcpdump -i any --immediate-mode --number
Only print a number of packets. You can use the -c flag for that
TShark
section contents
TShark is the terminal implementation of Wireshark. Both Tshark and Wireshark can read
captured network traffic (PCAPs).
There are resource advantages to using TShark, as you are keeping everything command line
and can pre-filter before you even ingest and read a file. A meaty pcap will take a while to be
ingested by Wireshark on the other hand. But once ingested, Wireshark proves to be the better
option. If you're in a hurry, TShark will give you the answers you need at break-neck speed!
Johannes Weber has an awesome blog with case studies on advanced pcacp analysis
Add
Add Colour
An essential part of making TShark aesthetically pop. Adding colour makes an analysts life
easier.
However the --color flag doesn't stack well with other flags, so be careful.
Add Time
By default, packets' time will show the time lasped between packets. This may not be the most
useful method if you're trying to quickly correleate time
#Get the UTC.Preferable in security, where we always try to keep security tooling at
tshark -r c42-MTA6.pcap -t ud
#Get the local year, month, date, and time the packet was captured
tshark -r c42-MTA6.pcap -t ad
Add Space
Default Tshark squishes the packet headers with no gaps. You can have the packet headers print
with gaps in between - which makes reading all that bit easier, using | pr -Ttd
In the screenshot, you can see how spacious and luxurious the top results are, and how dirty and
unreadable the second half is!
Add Readable Detail
What's a packet without the decoded text! Use the -x flag to get some insight into what's
occuring
tshark -r Voip-trace.pcap -x
Also, you can add verbose mode which includes all of Wireshark's drop-down details that you'd
normally get. This can yield a whole lot of data, so best to try and filter this bad boy
#just verbose
tshark -r Voip-trace.pcap -V
You'll also probably want to print the packet line too, with -P
Say a particular packet header captures your eye. You want to get as much info as possible on
that specific packet.
Now we get the full packet details for the specific packet that we wanted.
Ideal base for any TShark command
We can stack lots and lots of things in TShark, but there are some ideal flags that we've already
mentioned (or not yet mentioned) that form a solid base. Adding these flags in, or variations of
them, will usually always ensure we don't get too lost.
#read the pcacp, print time in UTC, verbose details, hex/ascii, print packet summary
tshark -r c42-MTA6.pcap -t ud -V -x -P -Y dns
To find out the options you have and the descriptions behind them, run this bad boy:
#the help will fail to do anything but don't worry about that
tshark -T help
Prepare for Elastic
Say for example we want to upload a packet into an ELK stack, we can print the PCAP in Elastic
format.
You know how in Wireshark you can open up the drop-down tabs to filter and get more info?
You can do that in TShark too. Though it just prints ALL of the tabs
# create a ps
tshark -T ps -r c42-MTA6.pcap > test.ps
## you can be verbose. This will make a CHUNGUS file though, very unwiedly
tshark -T ps -V -r c42-MTA6.pcap > verbose.ps
#You can convert it online in various places and turn it into a PDF
Raw PS
Size difference between -verbose flag on and off
Converted to PDF
Filtering
Glossary
-G is a GREAT flag. Using tshark -G help you can get an overview for everything the
Glossary can show you
Protocols
tshark -G protocols
#If you know the family of protocol you already want, grep for it
tshark -G protocols | grep -i smb
By Protocol
By IPs
You can can hunt down what a particular IP is up to in your packet
#For style points, pipe to ack so it will highlight when your IP appears!
| ack '192.168.137.56'
If you want to get a list of all the IPs involved in this traffic, get by Host IP and Destination IP
# you can use the -z flag, and we'll get onto that in more detail later
tshark -r c42-MTA6.pcap -q -z ip_hosts,tree
tshark -r c42-MTA6.pcap -q -z ip_srcdst,tree
Alternatively, just do a dirty grep regex to list out all the IPs
tshark -r c42-MTA6.pcap |
grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" |
sort -u
Using DisplayFilters
DisplayFilters are grep-like methods to control exactly what packets are shown to you. You can
use filters by themselves, or stack them. I regularly use DisplayFilter cheat sheets as a reminder
of all the filtering options avaliable.
The trick to getting specific answers in TShark is to use DisplayFilters at the right time. You
won't really use them for granularity at the beginning of an investigation. You may -Y
[protocol] from the beginning, but to use DisplayFilters you need to have particular values that
you are hunting for more information on. This inevitably comes as the investigation progresses.
Perhaps you want to see what kind of HTTP codes have appeared
Once you see a particular code (say 200), you can filter down for more info
#to punish yourself, you can make it verbose now you've filtered it down
tshark -r packet.pcapng -t ud -Y 'http.response.code==200' -x -V -P
You may have seen a particular IP, and you want to know what TLS activity it's had
Maybe you're interested to see what DNS activity a particular IP address had
Sometimes, you'll be using DisplayFilters that are difficult. Take example, VLAN querying for
STP. Specifically, we want to see how many topology changes there are.
The DisplayFilter for this is stp.flags.tc==1 . But putting that in doesn't seem to work for
me.....so I know the value I want to see. I COULD grep, but that would end up being difficult
Instead, I can utilise the -T fields flag, which allows me to use the -e flag that will only print
particular filters. In our case, all I want to do is find the packet number that gives the first 'yes'
for topology (which will =1).
Awesome, here we can see that packet 42 is the first time there is confirmation that the topology
has changed. We have stripped back the information to only show us exactly what we want:
packet number, and STP topography boolean
Now we know the packet number, let's go investgate more details on the VLAN number
responsible
tshark -r network.pcapng -V -P -c 42 |
tail -n120 |
ack -i 'topology' --passthru
Awesome, so we managed to achieve all of this by first sifting out all noise and focusing just on
the two fields of the display filter
Stats
The -z flag is weird. It's super useful to collect and aggregate stats about particular values.
Want to know all of the IPs in captured traffic AND sort them according to how prevelant they
are in traffic? -z is your guy
tshark -z help
Get Conversations
The -z flag can collect all the conversations that particular protocols are having. At the bottom,
it will provide a table of stats
IP conversations.
DHCP conversations
You can rip out some interesting details from DHCP packets. For example, the requested IP
address from the client, and the host name involved
SIP Conversations
Let's say we want to know when a local machine (192.168.1.26) communicated out to an external
public IP (24.39.217.246) on UDP
There are loads of ways to do this, but I'll offer two for now.
You can eyeball it. The advantadge of this method is that it shows the details of the
communication on the right-hand size, in stats form (bytes transferred for example). But isn't
helpful as you need to focus on every time the colours are on the same row, which is evidence
that the two IPs are in communication. So it isn't actually clear how many times these two IPs
communicated on UDP
We can collect a whole wealth of info on http stats with the -z flag
Part of -z expert will collect all the GET and POST requests. Just scroll down to Chats
It can be useful to know what MAC addresses have been involved in a conversation
#I picked FTP as a protocol to filter by, you don't have to. You could remove the -Y
tshark -r packet.pcapng -Y ftp -x -V -P | grep Ethernet | sort -u
To decrypt network https traffic, you need a decryption key. I'll go over how to get those another
time. For now, we'll assume we have one called tls_decrypt_key.txt.
This is another instance where, to be honest, Wireshark is just straight up easier to use. But for
now, I'll show you TShark. We use decryption keys like so: -o tls.keylog_file: key.txt
First, we need to sanity check that we actually have a working decryption key. Nice and simple,
let's get some stats about the traffic:
Nice and simple, there's not much going on here. Only 12 or so lines of info
Well, now let's compare what kind of data we get when we insert our decryption key.
Now that we've done that, let's go and hunt for some decrypted traffic to look at. We'll start by
ripping out all of the website names
Let's say we've seen a suspicious website (we'll choose web01.fruitinc.xyz), identify it's
corresponding packet number (675) and let's go and hunt for a stream number
Not bad, we've identified the stream conversation is 27. Now let's go and follow it
This screenshot shows what happens if we run the same without the decryption key
You get much of the same result if we check on HTTP interactions next
SMB
Be sure you're using DisplayFilters specific to SMB1 and SMB2
One of the quickest ways I know to get contexual info on what SMB files were interacted with is
smb.fid
SMB Users
I would then grep out for that username, for more info
Or fuck it, just grep for user and let the dice fall where the fates' deign.
TCP
Say you've captured traffic that may have had a reverse shell established.
We can quickly find out the TCP ports and respective IPs that were involved in the
communication. Though keep in mind reverse shells can also use UDP ports, and C2 can happen
over some wacky stuff like DNS and ICMP (which is ping's protocol).
Here, we get awesome results that let us know 192.168.2.244 was using 4444, which is
Metasploit's default port to use
Honestly, this is one of those things that is easier done in Wireshark. Going to Analyse, Follow,
and TCP Stream will reveal much.
If you absolutely want to do this in the command-line, Tshark will allow this. Under -z we can
see follow,X . Any protocol under here can be forced to show the stream of conversation.
We can compare what our command-line tshark implementation and our wireshark
implementation look like. Though it ain't as pretty, you can see they both deliver the same
amount of information. The advantadge of Tshark of course is that it does not need to ingest a
packet to analyse it, whereas Wireshark does which can come at an initial performance cost.
For other packets, to identify their stream conversation it saves the value as "Stream Index: X"
Get Credentials
In theory, -z credentials will collect the credentials in packets. I, however, have not had much
success with this tbh.
tshark -r ftp.pcap -z credentials
Extracting Stuff
Wireshark sometimes sucks when you want to quickly extract stuff and just look at it.
Fortunately, there are alternatives to be able to quickly get and look at files, images, credentials,
and more in packets.
section contents
NetworkMiner
NetworkMiner is GUI-based network traffic analysis tool. It can do lots of things, but the main
things we can focus on here is the ability to rapidly look at all the stuff.
BUT, NetworkMiner has some limitations in its FREE version, so we'll just focus on some of its
features.
You can fire up NetworkMiner from command-line to ingest a particular pcap
networkminer c42-MTA6.pcap
View Files
In the top bar, you can filter for all of the files in the traffic.
View Images
In the top bar, you can filter for all of the images in the traffic. It will include any images rendered
on websites, so you'll get a load of random crap too.
Once you see a file you find interesting, right-click and view the file
View Creds
Honestly, I find that these credential filters always suck. Maybe you'll have better luck
We can go and get all of the SMB files, and save it locally in a directory called
smb_exported_files
We get the original file, as if we ourselves downloaded it. However, unfortunately we do not get
the original metadata so the date and time of the file reflects our current, local time and date.
But nonetheless, we have the file!
Export HTTP Files with Decryption Key
In some situations, you will have a TLS decryption key in your hands. There may have been a file
in the traffic you want to get your hands on, so let's do it!
Let's say we're looking around the decrypted traffic and we see an interesting file referenced, in
this case an image:
To retrieve this image, we need only supply the decryption key whilst we export the object
Digital Forensics
If you're interested in digital forensics, there are some immediate authoritive sources I implore
you to look at:
13cubed's youtube content - Richard Davis is a DFIR legend and has some great learning
resources
Eric Zimmeraman's toolkit - Eric is the author of some incredibly tools, and it's worth
checking out his documentation on exactly how and when to use them.
section contents
volatility
section contents
There are loads of tools that can assist you with forensically exmaining stuff. Volatility is
awesome and can aid you on your journey. Be warned though, digital forensics in general are
resource-hungry and running it on a VM without adequate storage and resource allocated will
lead to a bad time.
In the Blue Team Notes, we'll use vol.py and vol3 (python2 and python3 implementation's of
Volatility, respectively). In my un-educated, un-wise opinon, vol2 does SOME things better than
vol3 - for example, Vol2 has plugins around browser history.
Because Volatility can take a while to run things, the general advice is to always run commands
and output them ( > file.txt ). This way, you do not need to sit and wait for a command to run
to re-check something.
Get Started
It's worth reviewing trhe Volatility docs, and make sure you've organised yourself as best as
possible before getting started.
One important prep task is to download the symbols table into your local machine
Reviewing options
Reading the docs and the -h help option let you know exactly what options you have available
Python2: Vol.py -h
Python3: vol3 -h
When you see a plugin you like the look of, you can -h on it to get more options
Volatility has options for Linux, Mac, and Windows. The notes here mainly focus on Windows
plugins, but the other OS' plugins are great fun too so give them a go sometime.
Get Basics
Get basic info about the dumped image itself
stat dumped_image.mem
Get Profile
#or just run it all in one. But you lose visibility to processes associated
vol3 -f 20210430-Win10Home-20H2-64bit-memdump.mem windows.getsids.GetSIDs|
tee | cut -f3,4 | sort -u | pr -Ttd
Vol2
In Volatility 2, you have to get the Profile of the image. This requires a bit more work. In theory,
you can use imageinfo as a brute-force checker....however, this takes a long time and is
probably not the best use of your valuable time.
I propose instead that you run the Vol3, which will suggest what OS and build you have. Then
pivot back to Vol2, and do the following:
#I then put these side to side in terminals, and try the different profiles with the
volatility -f image_dump.mem --profile=Win10x64_10586 systeminfo
Now that you have your Vol2 profile, you can leverage the plugins of both Vol2 and Vol3 with
ease.
Get Files
This plugin can fail on ocassion. Sometimes, it's just a case of re-running it. Other times, it may
be because you need to install the symbol-tables. If it continually fails, default to python2
volatility.
#stack this will all kinds of things to find the files you want
cut -f2 files.txt | sort | grep 'ps1'
cut -f2 files.txt | sort | grep 'exe'
cut -f2 files.txt | sort | grep 'evtx'
#pick the virtual address in the first columnm, circled in the first image below
#feed it into the --virtaddr value
vol3 -f image_dump.mem windows.dumpfiles.DumpFiles --virtaddr 0xbf0f6d07ec10
#If you know the offset address, it's possible to look at the ASCII from hex
hd -n24 -s 0x45BE876 image_dump.mem
Get Commands
##show IDs for parent and child, with some other stuff
cut -f1,2,3,9,10 pslist.txt
Retrieve the enviro variables surronding processes
#Here we get the ntuser.dat, which helps us figure our which user ran what
# We also get start time of a program, the program itself, and how long the progra
section contents
I've also got a repo with some emulated attack data to be extracted from some forensic
artefacts
Prefetch
You can query the prefetch directory manually
# I’d advise picking the -f flag, and picking on one of the prefetch files you see i
.\PECmd.exe -f ‘C:\Windows\prefetch\MIMIKATZ.EXE-599C44B5.pf’
# If you don’t know what file you want to process, get the whole directory. Will be
.\PECmd.exe -d 'C:\Windows\Prefetch' --csv . #dot at the end means write in current
Prefetch is usually enabled on endpoints and disabled on servers. To re-enable on servers, run
this:
Enable-MMAgent –OperationAPI;
Shimcache
Shimcache – called AppCompatCache on a Windows machine – was originally made to
determine interoperability issues between Windows versions and applications. Like prefetch, we
can leverage shimcache to identify evidence of execution on a machine when we do not have
event logs.
Another Eric Zimmerman tool called AppCompatCacheParser can give us insight into what was
run on the system.
Jump Lists
You can parse Jump Lists so they are very pretty....but if you're in a hurry, just run something
ugly like this
type C:\Users\*\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations\* |
flarestrings |
sort
Or use another of Eric's tools
#export to CSV
.\JLECmd.exe -d .\jump\ --all --mp --withDir --csv ./
#read the csv
Import-Csv .\20220322131011_AutomaticDestinations.csv |
select TargetIDAbsolutePath,InteractionCount,CreationTime,LastModified,TargetCreated
sort InteractionCount -desc
SRUM
I wrote a short thread on SRUM
SrumECmd_NetworkUsages_Output.csv
SrumECmd_AppResourceUseInfo_Output.csv
SrumECmd_Unknown312_Output.csv (occasionally)
Amcache
You can get amcache hive from C:\Windows\AppCompat\Programs\Amcache.hve . You may need
to copy the file by volume shadow or other means if it won't let you copy it directly.
select ProgramName,Fullpath,Filesize,FileDescription,FileVersionNumber,Created,Last*
sort -desc LastModified |
more
#You can exit this by pressing q
Certutil History
If you have an interactive session on the machine
certutil.exe -urlcache |
select-string -Pattern 'ocsp|wininet|winhttp|complete|update|r3' -NotMatch |
sort
WER
Windows Error Reporting (WER) is a diagnostic functionality that we don’t need to get too deep
in the weeds about for this post.
When an application crashes, WET gets some contextual info around the crash. This presents an
opportunity for us to retrieve DFIR data that may tell us something about the adversary or
malware
Take a look at the various directories, and eventually retrieve a .WER file
C:\ProgramData\Microsoft\Windows\WER\ReportArchive
C:\ProgramData\Microsoft\Windows\WER\ReportQueue
C:\Users\*\AppData\Local\Microsoft\Windows\WER\ReportArchive
C:\Users\*\AppData\Local\Microsoft\Windows\WER\ReportQueue
BITS
BITS is a lolbin and can be abused by threat actors to do a myriad of things
https://isc.sans.edu/forums/diary/Investigating+Microsoft+BITS+Activity/23281/
https://lolbas-project.github.io/lolbas/Binaries/Bitsadmin/
https://www.mandiant.com/resources/attacker-use-of-windows-background-intelligent-
transfer-service
Then use bitsparser tool
From Ryan
Good for catching coin miners that are too resource hungry
Can do this via SRUM, but this is ‘quicker’ as no need to parse the XMLs
Location
Collect a bunch of these, and then use some command line text editing:
Location
C:\Users\<username>\AppData\Local\ConnectedDevicesPlatform\L.<username>\ActivitiesCa
Opening this up in Excel, we can start to play around with the data.
You will get a folder with some goodies. The two CSVs to focus on are: ApplicationExecutionList,
WindowsTimeline. The former is easier to interpet than the latter
However, PcaGeneralDb0.txt contains some verbose meta data, so you can deploy something
like this to have both TXTs normalised and readable:
Program Compatibility Assistant also stores data in some Registry keys. Chatting with my man
@biffbiffbiff, we have some options to carve that out
Chainsaw
Chainsaw is an awesome executable for Windows event logs, that leverages sigma rules to carve
through the logs and highlight some of the suspicious activity that may have taken place.
It's relatively easy to install and use. You can take logs from a victim machine, and bring them
over to chainsaw on your DFIR VM to be examined, you just have to point chainsaw at the
directory the collected logs are in
.\chainsaw.exe hunt 'C:\CollectedLogs' --rules sigma_rules/ --mapping mapping_files/
Browser History
We can go and get a users' browers history if you have the machine.
You'll find the SQL DB file that stores the history in the following:
The GUI doesn't need much guidance, so lets chat command line.
List the tables, which are like ‘folders’ that contain categorised data
.tables
If you just run select * from downloads; , you’ll be annoyed by the messy output
To transform the data to something more useful to look at, try this, which will open it up in excel:
.excel
.headers on
select * from downloads;
And then if you tidy this up it's easy to see what the user downloaded and from where
You can also tidy it up with the following
Basics
Security Products Logs
Other Microsoft logs
Remote Management Logs
Cerutil History
Basics
Windows Event Logs can be found in C:\windows\System32\winevt\Logs\ . To understand the
general Event IDs and logs, you can read more here
But knowing which logs to pull of the hundreds can be disorientating. Fortunately, there really
aren’t that many to work with. This is for a myriad of reasons:
Most clients will not flick on additional logging features. This means that there are actually
few logs that provide security value
A lot of logs are diagnostic in nature, so we don’t have to pull these.
Even when certain logs do have security value - like PowerShell logs - if an incident
happened 2 months ago, and a partner did not store their logs elsewhere it is likely that
these logs have been overwritten.
Let’s signpost the logs you absolutely want to grab every time.
Here's a script that can automate collection for staple logs from below
Sysmon
C:\windows\System32\winevt\Logs\Sysmon.evtx
You’re never going to see Sysmon deployed. In 99% of the incidents I’ve been in, they never
have it.
But if you DO ever see sysmon, please do pull this log. It is designed to enrich logs with security
value, and is a standard tool for many SOCs / SIEMs
Holy Trinity
C:\windows\System32\winevt\Logs\Application.evtx
C:\windows\System32\winevt\Logs\Security.evtx
C:\windows\System32\winevt\Logs\System.evtx
These are the staple logs you will likely pull every single time.
These are the logs that will give you a baseline insight into an incident: the processes, the users,
the sign ins (etc)
C:\windows\System32\winevt\Logs\Microsoft-Windows-Windows
Defender%4Operational.evtx
We already get Defender alerts, but pulling the defender log is beneficial for log ingestion later.
We can correlate Defender alerts to particular processes.
PowerShell
C:\windows\System32\winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtx
By default, PowerShell logs are pretty trash. But I’ll pull them regardless if there is ever an AMSI /
PwSh related alert or artefact in the other logs. This will give insight into the commands an
adversary has run.
If you know the user who is involved in the suspicious process, there is a PowerShell history
artefact you can pull on.
C:\Users\
<username>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_his
tory.txt
Replace the username field with the username you have, and you will get a TXT file with the
history of the users PowerShell commands - sometimes!
C:\windows\System32\winevt\Logs\Microsoft-Windows-TerminalServices-RemoteConnectionM
C:\windows\System32\winevt\Logs\Microsoft-Windows-TerminalServices-LocalSessionManag
C:\windows\System32\winevt\Logs\Microsoft-Windows-WinRM%4Operational.evtx
Pull these to gain insight into the username, source IP address, and session time for RDP and
WinRM’s PowerShell remoting. This resource can advise further:
https://ponderthebits.com/2018/02/windows-rdp-related-event-logs-identification-tracking-
and-investigation/
300 & 200 will show the username and IP address that was part of the authentication
303 will show the above, but also session duration show BYTES IN and OUT, which may give
some context for data exfil (but vague context)
Miscellaneous logs
There are some other logs that you’ll pull on if the context is appropiate
C:\windows\System32\winevt\Logs\Microsoft-Windows-Shell-Core%4Operational.evtx
This can offer insight into execution from registry run keys
C:\windows\System32\winevt\Logs\Microsoft-Windows-Bits-Client%4Operational.evtx
C:Windows\System32\winevt\Logs\Microsoft-WindowsTaskScheduler%4Operational
Detail in scheduled tasks - though we would likely be able to get this telemtry elsewhere
Bitdefender:
C:\ProgramData\Bitdefender\Endpoint Security\Logs\
C:\ProgramData\Bitdefender\Desktop\Profiles\Logs\
C:\Program Files*\Bitdefender*\*\.db
C:\ProgramData\Bitdefender\Endpoint Security\Logs\Firewall\*.txt
Carbon Black
C:\ProgramData\CarbonBlack\Logs\*.log
C:\ProgramData\CarbonBlack\Logs\AmsiEvents.log
Cisco AMP
C:\Program Files\Cisco\AMP\*.db
Cylance / Blackberry
C:\ProgramData\Cylance\Desktop
C:\ProgramData\Cylance\Desktop\chp.db
C:\ProgramData\Cylance\Optics\Log
Databases were encrypted, so can’t be accessed easily. From Fireeye documentation, you can
get logs via command ‘xagt -g example_log.txt’.
C:\ProgramData\FireEye\xagt\*.db
F-Secure
C:\Users\*\AppData\Local\F-Secure\Log\*\*.log
C:\ProgramData\F-Secure\Antivirus\ScheduledScanReports\
C:\ProgramData\F-Secure\EventHistory\event
Kaspersky
C:\Windows\system32\winevt\logs
Malware Bytes
C:\ProgramData\Malwarebytes\Malwarebytes Anti-Malware\Logs\mbam-log-*.xml
C:\PogramData\Malwarebytes\MBAMService\logs\mbamservice.log
C:\Users\*\AppData\Roaming\Malwarebytes\Malwarebytes Anti-Malware\Logs\
C:\ProgramData\Malwarebytes\MBAMService\ScanResults\
McAfee
C:\ProgramData\McAfee\Endpoint Security\Logs\*.log
C:\ProgramData\McAfee\Endpoint Security\Logs_Old\*
C:\ProgramData\Mcafee\VirusScan\*
C:\ProgramData\McAfee\VirusScan\Quarantine\quarantine\*.db
C:\ProgramData\McAfee\DesktopProtection\*.txt
C:\ProgramData\Cyvera\Logs\*.log
Sentinel One:
C:\programdata\sentinel\logs\*.log, *.txt
C:\windows\System32\winevt\Logs\SentinelOne*.evtx
C:\ProgramData\Sentinel\Quarantine
Sophos:
C:\ProgramData\Sophos\Sophos Anti-Virus\logs\*.txt.
C:\ProgramData\Sophos\Endpoint Defense\Logs\*.txt
Symanetic
Trend Micro
C:\ProgramData\Trend Micro\
Webroot:
C:\ProgramData\WRData\WRLog.log
C:\ProgramData\Microsoft\Microsoft AntiMalware\Support\
C:\ProgramData\Microsoft\Windows Defender\Support\
C:\Windows\Temp\MpCmdRun.log
IIS (web) logs - can be application specific log directories and names at times
C:\Windows\System32\LogFiles\W3SVC*\*.log
C:\Inetpub\logs\LogFiles\*.log
C:\inetpub\logs\LogFiles\W3SVC*\*.log,
C:\Resources\Directory\*\LogFiles\Web\W3SVC*\*.log
MSQL
OneNote
C:\Users\*\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\LocalState
C:\Users\*\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\LocalState
C:\Users\*\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\LocalState
C:\Users\*\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\LocalState
C:\Users\*\AppData\Local\Packages\Microsoft.Office.OneNote_8wekyb3d8bbwe\LocalState
Teams
C:\Users\*\AppData\Roaming\Microsoft\Teams\IndexedDB\https_teams.microsoft.com_0.ind
C:\Users\*\AppData\Roaming\Microsoft\Teams\Local Storage\leveldb\
C:\Users\*\AppData\Roaming\Microsoft\Teams\Cache\
C:\Users\*\AppData\Roaming\Microsoft\Teams\desktop-config.json,lazy_ntfs,JSON config
C:\Users\*\AppData\Local\Packages\MicrosoftTeams_8wekyb3d8bbwe\LocalCache\Microsoft
OneDrive
C:\Users\*\AppData\Local\Microsoft\OneDrive\logs\
C:\Users\*\AppData\Local\Microsoft\OneDrive\settings\
C:\Users\*\OneDrive*\
C:\Users\*\Documents\Outlook Files\*.pst
C:\Users\*\Documents\Outlook Files\*.ost
C:\Users\*\AppData\Local\Microsoft\Outlook\*.pst
C:\Users\*\AppData\Local\Microsoft\Outlook\*.ost
C:\Users\*\AppData\Local\Microsoft\Outlook\*.nst
C:\Users\*\AppData\Local\Microsoft\Windows\INetCache\Content.Outlook\. #Attachments
Exchange:
C:\inetpub\wwwroot\aspnet_client\*\*\
C:\Inetpub\wwwroot\aspnet_client\system_web\*\*
ScreenConnect:
C:\Program Files*\ScreenConnect\App_Data\Session.db
C:\Program Files*\ScreenConnect\App_Data\User.xml
C:\ProgramData\ScreenConnect Client*\user.config
Splashtop
C:\windows\System32\winevt\Logs\Splashtop-Splashtop Streamer-Status%4Operational.evt
AnyDesk
C:\Users\*\AppData\Roaming\AnyDesk\*.trace
C:\ProgramData\AnyDesk\*.trace
C:\Users\*\Videos\AnyDesk\*.anydesk
C:\Users\*\AppData\Roaming\AnyDesk\connection_trace.txt
C:\ProgramData\AnyDesk\connection_trace.txt
C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\AnyDesk\*
Kaseya
C:\Users\*\AppData\Local\Kaseya\Log\KaseyaLiveConnect\
C:\ProgramData\Kaseya\Log\Endpoint\*
C:\Program Files*\Kaseya\*\agentmon.log
C:\Users\*\AppData\Local\Temp\KASetup.log
C:\Windows\Temp\KASetup.log
C:\ProgramData\Kaseya\Log\KaseyaEdgeServices\
RAdmin
C:\Windows\SysWOW64\rserver30\Radm_log.htm
C:\Windows\System32\rserver30\Radm_log.htm
C:\Windows\System32\rserver30\CHATLOGS\*\*.htm
C:\Users\*\Documents\ChatLogs\*\*.htm
TeamViewer
C:\Program Files*\TeamViewer\connections*.txt
C:\Program Files*\TeamViewer\TeamViewer*_Logfile*
C:\Users\*\AppData\Roaming\TeamViewer\MRU\RemoteSupport\*
RealVNC
C:\Users\*\AppData\Local\RealVNC\vncserver.log
mRemoteNG
C:\Users\*\AppData\Roaming\mRemoteNG\mRemoteNG.log
C:\Users\*\AppData\Roaming\mRemoteNG\confCons.xml
C:\Users\*\AppData\*\mRemoteNG\**10\user.config
Cerutil History
C:\Users\*\AppData\LocalLow\Microsoft\CryptnetUrlCache\MetaData\
Strings it homie!
USBs
The subkeys in this part of the registry will list the names of all the USBs connected to this
machine in the past.
Gather and corroborate USB names here for the next log.
HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR
You can leverage the next log along with your confirmed USB name from the registry, to identify
a window of time that this USB was plugged in to the computer.
C:\windows\inf\setupapi.dev.log
I never bother with this part, but you can also grab this EVTX
C:\windows\System32\winevt\Logs\Microsoft-Windows-Partition%4Diagnostic.evtx
and use chainsaw in search mode
# EventID 1006, for USB investigations, offers verbose results but is a good un' htt
You can probably also find some stuff from the Jumplist and LNK artefacts that have some
relevance to your USB investigation.
Reg Ripper
Harlan Carvey knows how to write a pretty mean tool or two. Reg Ripper is a forensic one
designed to aid you in parsing, timelining, and surgically interrograting registry hives to uncover
evidence of malice. Registry Collection made easy with this script right here.
# Here's a script that will pull collect all the registry files for you
wget -useb https://gist.githubusercontent.com/Purp1eW0lf/6bbb2c1e22fe64a151d7ab97be8
./Registry_Collection.ps1 #then execute
# Take your registry collected files from the above script. Prepare them for analysi
expand-archive C:\Users\*\Desktop\Huntress_Registry_Collection_2022_Dec_30_Fri_UTC+