Skip to content

Commit

Permalink
Merge pull request #189 from dwhite9/atomic-sudo
Browse files Browse the repository at this point in the history
Atomic sudo
  • Loading branch information
clr2of8 authored Apr 15, 2024
2 parents f43d87e + 762b07c commit 392533b
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 9 deletions.
1 change: 1 addition & 0 deletions Invoke-AtomicRedTeam.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
'New-AtomicTestDependency',
'Start-AtomicGUI',
'Stop-AtomicGUI',
'Set-Sudo'
'Invoke-SetupAtomicRunner',
'Invoke-GenerateNewSchedule',
'Invoke-RefreshExistingSchedule',
Expand Down
13 changes: 10 additions & 3 deletions Private/Invoke-ExecuteCommand.ps1
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
function Invoke-ExecuteCommand ($finalCommand, $executor, $executionPlatform, $TimeoutSeconds, $session = $null, $interactive) {
function Invoke-ExecuteCommand ($finalCommand, $executor, $elevationreq, $can_sudo, $executionPlatform, $TimeoutSeconds, $session = $null, $interactive) {
$null = @(
if ($null -eq $finalCommand) { return 0 }
$finalCommand = $finalCommand.trim()
Write-Verbose -Message 'Invoking Atomic Tests using defined executor'
if ($executor -eq "command_prompt" -or $executor -eq "sh" -or $executor -eq "bash") {
$execPrefix = "-c"
$execExe = $executor
if (($executor -eq "sh" -or $executor -eq "bash") -and ($elevationreq -eq $true) -and ($can_sudo -eq $true)) {
$execExe = "$(which sudo)"
$execPrefix = "$(which $executor) -c"
}
else {
$execExe = $executor
$execPrefix = "-c"
}

if ($executor -eq "command_prompt") {
$execPrefix = "/c";
$execExe = "cmd.exe";
Expand Down
7 changes: 6 additions & 1 deletion Public/Invoke-AtomicRunner.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@ function Invoke-AtomicRunner {
LogRunnerMsg "exiting script because $($artConfig.stopFile) exists"
exit
}

if ($IsLinux) {
# Check if linux Host can use sudo without a password.
$can_sudo = Set-Sudo($false)
if($can_sudo){
if ($shouldRename) { Invoke-Expression $("sudo hostnamectl set-hostname $newHostName") }
Invoke-Expression $("sudo shutdown -r now")
}
if ($shouldRename) { Invoke-Expression $("hostnamectl set-hostname $newHostName") }
Invoke-Expression $("shutdown -r now")
}
Expand Down
9 changes: 8 additions & 1 deletion Public/Invoke-AtomicTest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ function Invoke-AtomicTest {

Write-Debug -Message 'Gathering final Atomic test command'

# Check if linux Host can use sudo without a password.
$can_sudo = Set-Sudo($false)

if ($CheckPrereqs) {
Write-KeyValue "CheckPrereq's for: " $testId
Expand All @@ -441,7 +443,12 @@ function Invoke-AtomicTest {
}
Write-KeyValue "GetPrereq's for: " $testId
if ( $test.executor.elevation_required -and -not $isElevated) {
if ($can_sudo -eq $true) {
Write-Host -ForegroundColor Yellow "Elevation required but not provided, but host supports passwordless sudo"
}
else{
Write-Host -ForegroundColor Red "Elevation required but not provided"
}
}
if ($nul -eq $test.dependencies) { Write-KeyValue "No Preqs Defined"; continue }
foreach ($dep in $test.dependencies) {
Expand Down Expand Up @@ -484,7 +491,7 @@ function Invoke-AtomicTest {
$startTime = Get-Date
$final_command = Merge-InputArgs $test.executor.command $test $InputArgs $PathToPayloads
if (Get-Command 'Invoke-ARTPreAtomicHook' -errorAction SilentlyContinue) { Invoke-ARTPreAtomicHook $test $InputArgs }
$res = Invoke-ExecuteCommand $final_command $test.executor.name $executionPlatform $TimeoutSeconds $session -Interactive:$Interactive
$res = Invoke-ExecuteCommand $final_command $test.executor.name $test.executor.elevation_required $can_sudo $executionPlatform $TimeoutSeconds $session -Interactive:$Interactive
Write-Host "Exit code: $($res.ExitCode)"
if (Get-Command 'Invoke-ARTPostAtomicHook' -errorAction SilentlyContinue) { Invoke-ARTPostAtomicHook $test $InputArgs }
$stopTime = Get-Date
Expand Down
23 changes: 19 additions & 4 deletions Public/Invoke-SetupAtomicRunner.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ function Invoke-SetupAtomicRunner {
}
else {
# linux and macos check - doesn't auto-elevate
if ((id -u) -ne 0 ) {
# Check if current user has passwordless sudo privleges. If not, attempt to configure it for current user.
$can_sudo = Set-Sudo($true)
if ($can_sudo -eq $true -and (sudo id -u) -ne 0 ) {
Throw "You must run the Invoke-SetupAtomicRunner script as root"
exit
}
elseif ($can_sudo -eq $false -and (id -u) -ne 0 ) {
Throw "You must run the Invoke-SetupAtomicRunner script as root"
exit
}
Expand Down Expand Up @@ -86,22 +92,31 @@ function Invoke-SetupAtomicRunner {
}
}
else {

# sets cronjob string using basepath from config.ps1
$pwshPath = which pwsh
$job = "@reboot root sleep 60;$pwshPath -Command Invoke-KickoffAtomicRunner"
$job = "@reboot $env:USER sleep 60;$pwshPath -Command Invoke-KickoffAtomicRunner"
$exists = cat /etc/crontab | Select-String -Quiet "KickoffAtomicRunner"
#checks if the Kickoff-AtomicRunner job exists. If not appends it to the system crontab.
if ($null -eq $exists) {
$(Write-Output "$job" >> /etc/crontab)
if ($null -eq $exists -and $can_sudo -eq $true) {
$(Write-Output "$job" | sudo tee -a /etc/crontab)
write-host "setting cronjob"
}
elseif ($null -eq $exists -and $can_sudo -eq $false) {
$(Write-Output "$job" >> /etc/crontab)
write-host "setting cronjob"
}
else {
write-host "cronjob already exists"
}
}

# Add Import-Module statement to the PowerShell profile
$root = Split-Path $PSScriptRoot -Parent
if($IsLinux -or $IsMacOS){
mkdir (Split-Path $PROFILE)
touch $PROFILE
}
$pathToPSD1 = Join-Path $root "Invoke-AtomicRedTeam.psd1"
$importStatement = "Import-Module ""$pathToPSD1"" -Force"
New-Item $PROFILE -ErrorAction Ignore
Expand Down
33 changes: 33 additions & 0 deletions Public/Set-Sudo.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
function Set-Sudo ($set_sudo) {

$ErrorActionPreference = "Stop"
$env:SUDO_ASKPASS="/bin/false"

try {
if ((sudo -A whoami) -and ((sudo grep -r $env:USER /etc/sudoers | grep NOPASSWD:ALL) -or (sudo grep -r $env:USER /etc/sudoers.d | grep NOPASSWD:ALL))){

if($set_sudo){
Write-Host "Passwordless logon already configured.`n"
}
$nopassword_enabled = $true

}
elseif ($set_sudo -eq $true){

Write-Host "Configuring Passwordless logon...`n"
Write-Output "$env:USER ALL=(ALL) NOPASSWD:ALL" > /tmp/90-$env:USER-sudo-access
sudo install -m 440 /tmp/90-$env:USER-sudo-access /etc/sudoers.d/90-$env:USER-sudo-access
rm -f /tmp/90-$env:USER-sudo-access
$nopassword_enabled = $true
}
else {
write-host "Host not configured for passwordless logon"
$nopassword_enabled = $false
}
}
catch {
write-host "Error configuring passwordless logon"
$nopassword_enabled = $false
}
return $nopassword_enabled
}

0 comments on commit 392533b

Please sign in to comment.