Beyond


This is the beyond page that an additional post enumeration and assessment are conducted as SYSTEM after compromising the target system.

Scheduled Tasks


PS C:\Users\Administrator> Get-ScheduledTask | where {$_.TaskPath -notlike "\Microsoft*" } | ft TaskName,TaskPath,State
 
TaskName                           TaskPath State
--------                           -------- -----
Clean builds and build definitions \        Ready
Restore Git repos                  \        Ready

Clean builds and build definitions


ps c:\Users\Administrator> cmd /c schtasks /QUERY /TN "\Clean builds and build definitions" /V /FO LIST
 
folder: \
hostname:                             WORKER
taskname:                             \Clean builds and build definitions
next run time:                        2023-11-24 03:41:00
status:                               Ready
logon mode:                           Interactive/Background
last run time:                        2023-11-24 03:40:00
last result:                          0
author:                               WORKER\Administrator
task to run:                          C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass c:\Users\restorer\source\repos\Clean-Builds.ps1
start in:                             N/A
comment:                              N/A
scheduled task state:                 Enabled
idle time:                            Disabled
power management:                     Stop On Battery Mode, No Start On Batteries
run as user:                          WORKER\restorer
delete task if not rescheduled:       Disabled
stop task if runs x hours and x mins: 72:00:00
schedule:                             Scheduling data is not available in this format.
schedule type:                        One Time Only, Minute 
start time:                           08:24:00
start date:                           2020-08-13
end date:                             N/A
days:                                 N/A
months:                               N/A
repeat: Every:                        0 Hour(s), 1 Minute(s)
repeat: Until: Time:                  None
repeat: Until: Duration:              Disabled
repeat: Stop If Still Running:        Disabled

executing c:\Users\restorer\source\repos\Clean-Builds.ps1 every minute as the restorer account

Clean-Builds.ps1


PS C:\Users\Administrator> cat c:\Users\restorer\source\repos\Clean-Builds.ps1
# Reference: https://docs.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-server-rest-5.0
#
######################################################################################################
 
$projects = @{}
#$tfsBaseUrl = "http://devops.worker.htb/ekenas/"				# This url is for external access, only used for testing
$tfsBaseUrl = "http://127.0.0.1:8080/ekenas/"					# This url is for internal access, used by the local restorer account
$pat = "7xqg2p3sxh65mysw3qthykd4iwgonjm2qwv4sm2zawe4hcbsb2pa"	# This PAT (Full Access) has been created by the Administrator Account in the Azure Devops Portal
																# It needs to be renewed every 12 month since it will expire after this timeout
																# If it is not renewed after 12 months the builds won't be cleaned by this script since the PAT is rejected
 
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)"))
$header = @{authorization = "Basic $token"}
 
$now = Get-Date
																
# -------------------------------------------------------------------------------------------------------------------------------------------------
# In case of users getting locked out, increase these values to allow the definitions and builds to exist for a longer time before wiping them
# Note that when deleting a build definition, all builds executed on that definition will be deleted as well. This is mainly a concern for the
# PartsUnlimited Project, since it is only there a user can create definitions.
Set-Variable DEFINITION_MAX_AGE_MINUTES -Option Constant -Value 1
Set-Variable BUILD_MAX_AGE_MINUTES -Option Constant -Value 3
# -------------------------------------------------------------------------------------------------------------------------------------------------
 
# =================================================================================================================================================																
 
function Get-Projects {
 
	$projectsUrl = "$($tfsBaseUrl)_apis/projects?api-version=5.0"
 
	$projects = Invoke-RestMethod -Uri $projectsUrl -Method Get -ContentType "application/json" -Headers $header
	
	return $projects.value
}
 
function Get-BuildDefinitions {
	param (
		[string]$projectName
	)	
 
	$definitionUrl = "$($tfsBaseUrl)/$($projectName)/_apis/build/definitions?includeLatestBuilds=true&api-version=5.0" 
	$definitions = Invoke-RestMethod -Uri $definitionUrl -Method Get -ContentType "application/json" -Headers $header
	$definitionsMarkedForDeletion = @()
 
	$definitions.value | ForEach-Object {
		
		$createdDate = [datetime]::Parse($_.createdDate)
		$timeDifference = $now - $createdDate
		
		# Definition that has been executed at least once will be marked for deletion
		if ($_.latestCompletedBuild -ne $null) { 
			$definitionsMarkedForDeletion += $_
		}
			
		# Definition is older than specified DEFINITION_MAX_AGE_MINUTES minutes will be marked for deleteion
		if ($timeDifference.TotalMinutes -ge $DEFINITION_MAX_AGE_MINUTES) { 
			$definitionsMarkedForDeletion += $_
		}
	}
	
	return $definitionsMarkedForDeletion
}
 
function Get-Builds {
	param (
		[string]$projectName
	)
		
	# Get Builds	
    $buildUrl = "$($tfsBaseUrl)/$($projectName)/_apis/build/builds?api-version=5.0"
    $builds = Invoke-RestMethod -Uri $buildUrl -Method Get -ContentType "application/json" -Headers $header
	$buildsMarkedForDeletion = @()
	
	$builds.value | ForEach-Object {
	
		$queueTime = [datetime]::Parse($_.queueTime)
		$timeDifference = $now - $queueTime
		
		# Build that has been executed will be marked for deletion
		if ($_.finishTime -ne $null) { 
			$buildsMarkedForDeletion += $_
		}
			
		# Build is older than specified value minutes will be marked for deleteion
		if ($timeDifference.TotalMinutes -ge $BUILD_MAX_AGE_MINUTES) { 
			$buildsMarkedForDeletion += $_
		}
	}
	
	return $buildsMarkedForDeletion
}
 
function Delete-BuildDefinitions {	
	param (
		[Parameter()]
		[string]$projectName,
		
		[Parameter()][PSCustomObject[]]
		$definitions
	)
	
	if ($definitions.Count -gt 0)
	{
		Write-Host "Deleting the following definitions in $projectName"
		Write-Host "--------------------------------------------------"
		
		$definitions | ForEach-Object {				
		
			Write-Host "`t" $_.name
						
			$deleteDefinitionUrl = "$($tfsBaseUrl)/$($projectName)/_apis/build/definitions/$($_.id)?api-version=5.0"
			$result = Invoke-RestMethod -Uri $deleteDefinitionUrl -Method Delete -ContentType "application/json" -Headers $header
		}
	}		
}
 
function Delete-Builds {
	param (
		[Parameter()]
		[string]$projectName,
	
		[Parameter()]
		[PSCustomObject[]]$builds
	)
		
	if ($builds.Count -gt 0)
	{
		Write-Host "Deleting the following builds in $projectName"
		Write-Host "---------------------------------------------"
	
		$builds | ForEach-Object {				
		
			Write-Host "`t" $_.id			
		
			$deleteBuildUrl = "$($tfsBaseUrl)/$($projectName)/_apis/build/builds/$($_.id)?api-version=5.0"
			$result = Invoke-RestMethod -Uri $deleteBuildUrl -Method Delete -ContentType "application/json" -Headers $header
		}
	}
}
 
# ==================================================================================================================================================
 
$definitions = Get-BuildDefinitions "PartsUnlimited"
 
$projects = Get-Projects
 
$projects | ForEach-Object {
	
	$projectName = $_.name
	$builds = Get-Builds $projectName	
	
	Delete-Builds $projectName $builds	
}
 
# We have to delete the builds before deleting the definitions due to the fact that builds can be seen in the Agent log otherwhise
Delete-BuildDefinitions "PartsUnlimited" $definitions

Restore Git repos


ps c:\Users\Administrator> cmd /c schtasks /QUERY /TN "\Restore Git repos" /V /FO LIST
 
folder: \
hostname:                             WORKER
taskname:                             \Restore Git repos
next run time:                        2023-11-24 03:44:00
status:                               Ready
logon mode:                           Interactive/Background
last run time:                        2023-11-24 03:34:01
last result:                          0
author:                               WORKER\Administrator
task to run:                          C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass c:\Users\restorer\source\repos\Restore-Repos.ps1
start in:                             N/A
comment:                              N/A
scheduled task state:                 Enabled
idle time:                            Disabled
power management:                     Stop On Battery Mode, No Start On Batteries
run as user:                          WORKER\restorer
delete task if not rescheduled:       Disabled
stop task if runs x hours and x mins: 72:00:00
schedule:                             Scheduling data is not available in this format.
schedule type:                        One Time Only, Minute 
start time:                           08:24:00
start date:                           2020-08-13
end date:                             N/A
days:                                 N/A
months:                               N/A
repeat: Every:                        0 Hour(s), 10 Minute(s)
repeat: Until: Time:                  None
repeat: Until: Duration:              Disabled
repeat: Stop If Still Running:        Disabled

executing c:\Users\restorer\source\repos\Restore-Repos.ps1 every 10 minutes as the restorer account

Restore-Repos.ps1


PS C:\Users\Administrator> cat c:\Users\restorer\source\repos\Restore-Repos.ps1
# Restore-repos.ps1
$Repos = @("alpha","dimension","lens","solid-state","spectral","story","twenty","cartoon","SmartHotel360")
 
$Repos | foreach {	
	Write-Host "Processing $_"
	cd C:\Users\restorer\source\repos\$_
	cmd /c 'git.exe push origin --force'
	cmd /c 'git.exe ls-remote --heads origin | grep.exe -ve "master$" | cut.exe -d / -f3 | xargs.exe git.exe push origin --delete'
	cd ..
}

Administrator user


ps c:\Users\Administrator> tree /F /A
tree /F /A
Folder PATH listing
Volume serial number is 32D6-9041
c:.
|   azure-devops.exe
|   
+---3D Objects
+---Contacts
+---Desktop
|       root.txt
|       
+---Documents
|       Add-Restorer-Tasks.ps1
|       Deny-Write.ps1
|       Revoke-IIS-PrimaryTokenPrivilege.ps1
|       UserRights.psm1
|       
+---Downloads
+---Favorites
+---Links
+---Music
+---Pictures
+---Saved Games
+---Searches
\---Videos

Add-Restorer-Tasks.ps1


PS C:\Users\Administrator> cat Documents\Add-Restorer-Tasks.ps1
# Resources
#https://www.windows-commandline.com/schedule-tasks-command-line/
 
Import-Module .\UserRights.psm1
 
Grant-UserRight -Account restorer -Right SeBatchLogonRight
 
##############################################################################################################################################################
# These values can be changed to increase/decrease the cleaning operations
# A to HIGH value will make it likelly to cause spoilers, due to the fact that one htb user might see what another has been up to.
# A to LOW value might meen the operation might not have time to finish before the cleaning kicks in.
# I have added some checks in the build and build definitions cleaning script (Clean-Builds.ps1) that checks:
#   1. if a build has finished before removing it
#	2. if a build definition has been "executed" once before removing it
# Due to the fact of the above checks I have set the cleaning timeout to a lower value for the builds and build definitions than the git repo restore
##############################################################################################################################################################
 
$GIT_RESTORE_TIMEOUT = 10
$CLEAN_BUILDS_TIMEOUT = 1
 
##############################################################################################################################################################
 
 
# Tasks to restore git repos
schtasks /create /RU restorer /RP IHopeThisPassword1sSafeEnough /SC minute /MO $GIT_RESTORE_TIMEOUT /TN "Restore Git repos" /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass c:\Users\restorer\source\repos\Restore-Repos.ps1"
 
# Task to clean builds and build definitions
schtasks /create /RU restorer /RP IHopeThisPassword1sSafeEnough /SC minute /MO $CLEAN_BUILDS_TIMEOUT /TN "Clean builds and build definitions" /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ep bypass c:\Users\restorer\source\repos\Clean-Builds.ps1"

Generating those 2 scheduled tasks above

Deny-Write.ps1


ps c:\Users\Administrator> cat Documents\Deny-Write.ps1
$inheritanceflag = [system.security.accesscontrol.inheritanceflags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
$propagationflag = [system.security.accesscontrol.propagationflags]:: None
$accesscontroltype = $objtype = [system.security.accesscontrol.accesscontroltype]::Deny
 
$DenyWriteRule = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS APPPOOL\DEFAULTAPPPOOL", "write", $InheritanceFlag, $PropagationFlag, $AccessControlType)
 
$directories = get-childitem w:\ -Directory
 
$directories | foreach {
	$acl = Get-Acl $_.fullname
	$acl.SetAccessRule($DenyWriteRule)
	$acl | Set-Acl $_.fullname
}

denies the iis apppool\defaultapppool account from accessing the w: drive

Revoke-IIS-PrimaryTokenPrivilege.ps1


PS C:\Users\Administrator> cat Documents\Revoke-IIS-PrimaryTokenPrivilege.ps1
Import-Module .\UserRights.psm1
 
# Note: The SeAssignPrimaryTokenPrivilege seems to be restored for "iis apppool\defaultapppool" after a little while/reboot
Revoke-UserRight "iis apppool\defaultapppool" -Right SeAssignPrimaryTokenPrivilege
Revoke-UserRight "iis apppool\.NET v4.5" -Right SeAssignPrimaryTokenPrivilege
Revoke-UserRight "iis apppool\.NET v4.5 Classic" -Right SeAssignPrimaryTokenPrivilege

Attempts to revoke the SeAssignPrimaryTokenPrivilege from the following accounts;

  • iis apppool\defaultapppool
  • iis apppool\.NET v4.5
  • iis apppool\.NET v4.5 Classic

This obviously failed

UserRights.psm1


This appears to be an external resource. mostly identical to this

restorer User


PS C:\Users\restorer> ls
 
 
    Directory: C:\Users\restorer
 
 
Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-r---       2018-09-15     09:12                Desktop                                                               
d-r---       2020-07-07     17:53                Documents                                                             
d-r---       2018-09-15     09:12                Downloads                                                             
d-r---       2018-09-15     09:12                Favorites                                                             
d-r---       2018-09-15     09:12                Links                                                                 
d-r---       2018-09-15     09:12                Music                                                                 
d-r---       2018-09-15     09:12                Pictures                                                              
d-----       2018-09-15     09:12                Saved Games                                                           
d-----       2020-07-07     17:53                source                                                                
d-r---       2018-09-15     09:12                Videos                                                                
-a----       2020-07-08     19:46            419 Note.txt                                                              

Notes.txt


ps c:\Users\restorer> cat Note.txt
Interesting, very interesting...
 
You reached this location and that was not intented.
This account is has been created to prevent cheating.
 
It will actually restore the git repos and clean up build logs and definitions
on the Azure Devops Server in an attempt to prevent spoilers.
 
Please - pretty please - do not modify anything here since that might spoil solutions for others.
 
Kind Regards
- ekenas

Interesting..

source\repos


PS C:\Users\restorer> ls source
 
 
    Directory: C:\Users\restorer\source
 
 
Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----       2020-07-22     01:11                repos                                                                 
 
 
PS C:\Users\restorer> cd source/repos ; ls
 
 
    Directory: C:\Users\restorer\source\repos
 
 
Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----       2020-07-07     17:59                alpha                                                                 
d-----       2020-07-07     17:59                cartoon                                                               
d-----       2020-07-07     17:59                dimension                                                             
d-----       2020-07-07     17:59                lens                                                                  
d-----       2020-07-09     16:32                SmartHotel360                                                         
d-----       2020-07-07     17:59                solid-state                                                           
d-----       2020-07-07     17:59                spectral                                                              
d-----       2020-07-07     17:59                story                                                                 
d-----       2020-07-07     17:59                twenty                                                                
-a----       2020-07-22     01:10           5786 Clean-Builds.ps1                                                      
-a----       2020-07-09     16:16            342 Clone-Repos.ps1                                                       
-a----       2020-07-09     16:16            397 Restore-Repos.ps1                                                     

This is where all the sources live

Clone-Repos.ps1


ps c:\Users\restorer\source\repos> cat Clone-Repos.ps1
# Clone-repos.ps1
 
# Repos in SmartHotel360 project
$SmartHotel360Repos = @("alpha","cartoon","dimension","lens","solid-state","spectral","story","twenty","SmartHotel360")
$SmartHotel360Repos | foreach {	
	Write-Host "Processing $_"
	git clone http://restorer:IHopeThisPassword1sSafeEnough@127.0.0.1:8080/ekenas/SmartHotel360/_git/$_
}

restorer:IHopeThisPassword1sSafeEnough really?