diff --git a/Powershell/PowerShellSample.ps1 b/Powershell/PowerShellSample.ps1 index 922fadd..b622e2f 100644 --- a/Powershell/PowerShellSample.ps1 +++ b/Powershell/PowerShellSample.ps1 @@ -1,13 +1,22 @@ <# .SYNOPSIS This script demonstrate how to use the Springfield service from Powershell - -.NOTE + via the Springfield REST API. +.DESCRIPTION + The script performs the following: + - Create a Springfield job + - Wait for preparation machine associated with the job to be ready + - Inject test application to be fuzzed and associated seed files into the virtual machine + - Submit the job + - Monitor the job progress until it starts fuzzing + - Wait until at least one result is reported + - Delete the job +.REMARK The API token can be generated from the Springfield website on the setting page #> param( # URL to the Springfield service - $springfieldUri = "https://www.alamosand.azurewebsites.net", + $springfieldUri = "https://www.alamohendersonville.com", # Springfield Account Id [Parameter(Mandatory=$true)] @@ -17,81 +26,68 @@ param( [Parameter(Mandatory=$true)] $apiToken, - # The Azure subscription ID + # Azure subscription ID [Parameter(Mandatory=$true)] $subscriptionId, - - # Resource group containing the stroage account - [Parameter(Mandatory=$true)] - $resourceGroup, - # The resource group of the storage account + # Name of Azure storage account where to upload the test payload [Parameter(Mandatory=$true)] $storageAccountName, - # The key of the storageAccount + # Azure storage account key [Parameter(Mandatory=$true)] $storageAccountKey, # The path to the folder containing the application to fuzz - $testFileFolder="$PSScriptRoot\..\SampleFuzzingJobs\Demofuzz", + $testFileFolder = "$PSScriptRoot\..\SampleFuzzingJobs\Demofuzz", # Set of job parameters. This correspond to the answer to the wizard's questionnaire $jobParameters = @{ seedDir = 'c:\DemoFuzz\Data' - seedExtension = '.bin' - testDriverExecutable = 'c:\DemoFuzz\demofuzz.exe' - testDriverExeType = 'x86' - testDriverParameters = '"%testfile%"' - closesItself = $true - maxDurationSeconds = 5 - runsInLessThan5 = $true - canRunRepeat = $true - canTestDriverBeRenamed = $true - singleOsProcess = $true - sysprepCompleted = $false - promptValidationSysprep = $false + seedExtension = '.bin' + testDriverExecutable = 'c:\DemoFuzz\demofuzz.exe' + testDriverExeType = 'x86' + testDriverParameters = '"%testfile%"' + closesItself = $true + maxDurationSeconds = 5 + runsInLessThan5 = $true + canRunRepeat = $true + canTestDriverBeRenamed = $true + singleOsProcess = $true + sysprepCompleted = $false + promptValidationSysprep = $false } - ) # Extract name of sample from directory name $sampleName = $(Split-Path $testFileFolder -Leaf) - <# .SYNOPSIS Helper function used to upload files as blob to the azure storage account #> function UploadFileToAzure ( - # Path to the file to be uploaded to the storageAccount - [Parameter(Mandatory=$true)] $sourceFileName -) { - - $targetStorage = Get-AzureRmStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroup - - $destContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey - - $containerName = "sample" - $container = Get-AzureStorageContainer -Context $destContext -Name $containerName -ErrorAction SilentlyContinue + # Path to the file to be uploaded to the storage account + [Parameter(Mandatory=$true)] $sourceFileName, + $containerName = "sample" +) { + $destContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey + $container = Get-AzureStorageContainer -Context $destContext -Name $containerName -ErrorAction SilentlyContinue if(-not $container) { $container = New-AzureStorageContainer -Name $containerName -Context $destContext } - $blobName = Split-Path $sourceFileName -Leaf - $blob = Set-AzureStorageBlobContent -Context $destContext -Container $containerName -File $sourceFileName -Blob $blobName -Force - $blobSas = New-AzureStorageBlobSASToken -Context $destContext -Container $containerName -Blob $blobName -Permission r -FullUri -ExpiryTime ([System.DateTime]::Now.AddHours(1)) - Write-Host "Blob SAS: $blobSas" return $blobSas } <# .SYNOPSIS - Compress the test file to zip and inject an install script into the archive + Zip the test payload and add an script into the archive + to automate job submission from the VM. #> function CreateTestZipFile( # Path to the source directory containing the test payload @@ -101,23 +97,27 @@ function CreateTestZipFile( ) { Write-Host "Creating zip file containing the application to test" - $installScriptContent = @" - '$($jobParameters | ConvertTo-Json)' | Set-Content c:\Springfield\JobParams.json - & c:\Springfield\Springfield.Prevalidation.UI.Console\Springfield.Prevalidation.UI.Console.exe -unattend -"@ - $tmpDir = [System.IO.Path]::GetTempFileName() rm $tmpDir $dir = md $tmpDir + + # Copy test driver and seed files Copy-Item $testFileFolder $tmpDir -Recurse $testZipPath = "$tmpDir\$sampleName.zip" $directoryToZip = "$tmpDir\$sampleName" - Set-Content -Path "$directoryToZip\install.ps1" -Value $installScriptContent + # Copy job parameters + $jobParameters | ConvertTo-Json | Set-Content -Path "$directoryToZip\JobParams.json" + + # Generate script to automate job submission + $submitJobScriptContent = @" + '$($jobParameters | ConvertTo-Json)' | Set-Content c:\Springfield\JobParams.json + & c:\Springfield\Springfield.Prevalidation.UI.Console\Springfield.Prevalidation.UI.Console.exe -unattend +"@ + Set-Content -Path "$directoryToZip\install.ps1" -Value $submitJobScriptContent Add-Type -assembly "system.io.compression.filesystem" - - if (Test-Path $testZipPath ){ + if (Test-Path $testZipPath){ Write-host "$testZipPath already exist: removing it" Remove-Item $testZipPath } @@ -127,106 +127,17 @@ function CreateTestZipFile( return $testZipPath } -<# -.SYNOPSIS - This function shows how to interact with the Springfield service via the SDK -.DESCRIPTION - The function does the following: - - Create a job - - Wait for preparation machine associated with the job to be ready - - Inject test application to be fuzzed and associated seed files - - Monitor the job progress until it starts fuzzing - - Wait until at least one result is reported - - Delete the job -#> -function CreateAndMonitorJob { - param( - # The list of uris of the dependencies that needs to be donwloaded on the preparation machine - [Parameter(Mandatory=$true)] $dependencyUris - ) - - $uri = $springfieldUri - - $pollingInternavalInSeconds = 60*3 - - $headers = @{ - "SpringfieldApiToken" = $apiToken - "Content-Type" ="application/json" - } - - $osImages = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/osimages" -Headers $headers -Verbose - - Write-Host "Creating a job" - $jobInfo = Invoke-RestMethod -Method POST -Uri "$uri/api/accounts/$accountId/jobs?osImageId=$($osImages[0].Id)" -Headers $headers -Verbose - - $jobId = $jobInfo.Id - Write-Host "job $jobId created" - - while (-not $jobInfo.IsPreparationVMReady) { - Write-Host "Waiting for the preparation vm to be ready" - Start-Sleep -Seconds $pollingInternavalInSeconds - $jobInfo = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose - } - - Write-Host "Retrieving the machine name" - $machineName = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId/customermachine" -Headers $headers -Verbose - Write-Host "Machine name $machineName retrieved" - - # The command to execute on the job preparation machine - $executionCommand = "powershell.exe -ExecutionPolicy Unrestricted -Command `".\UnzipAndRun.ps1 -zipFile $sampleName.zip -scriptToRun install.ps1 -outputDir 'c:\$sampleName'`"" - - $commandParams = @{ - "command" = $executionCommand - "dependencyUris" = $dependencyUris - } | ConvertTo-Json - - Write-Host "Submitting command for execution $commandParams" - $commandInfo = Invoke-RestMethod -Method POST -Uri "$uri/api/accounts/$accountId/jobs/$jobId/machines/$machineName/command" -Headers $headers -Body $commandParams -ContentType 'application/json' -Verbose - - while ($commandInfo.ExecutionState.IsPendingState) { - Write-Host "Waiting for the command to finish executing" - Start-Sleep -Seconds $pollingInternavalInSeconds - $commandInfo = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId/machines/$machineName/command/$($commandInfo.CommandId)" -Headers $headers -Verbose - } - - if ( $commandInfo.ExecutionState.IsErrorState ) { - throw "Error during execution of custom command : $($commandInfo.ExecutionState.GetError)" - } - - Write-Host "Monitoring command job status until fuzzing or error" - while (-not $jobInfo.IsFuzzing ) { - Write-Host "Waiting for the job to start fuzzing" - Start-Sleep -Seconds $pollingInternavalInSeconds - $jobInfo = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose - } - - Write-Host "Poll until we get at least one result" - $results = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId/results" -Headers $headers -Verbose - - while ($results.Count -eq 0){ - Start-Sleep -Seconds $pollingInternavalInSeconds - $results = Invoke-RestMethod -Method GET -Uri "$uri/api/accounts/$accountId/jobs/$jobId/results" -Headers $headers -Verbose - } - - Write "Got $($results.Count) results $results" - Write-Host "Deleting the job" - - Invoke-RestMethod -Method DELETE -Uri "$uri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose -} - -##### Login into Azure -Import-Module AzureRm.Storage -$account = Login-AzureRmAccount -SubscriptionId $subscriptionId - ##### # Preparing the test payload to be copied onto the VM. This includes test driver binaries, seed files # and the job prameters (a Json blob containing answer to the wizard's questions) $testZipPath = CreateTestZipFile -testFileFolder $testFileFolder -jobParameters $jobParameters - ##### # Upload all the test files to the azure storage account -Write-Host "Uploading the zip file contianing the application to test" +Import-Module AzureRm.Storage +$account = Login-AzureRmAccount -SubscriptionId $subscriptionId + +Write-Host "Uploading the archive with the test payload to a storage account" $dependencyUris = ` @( UploadFileToAzure $testZipPath @@ -236,4 +147,69 @@ $dependencyUris = ` ##### # Create the Springfield Job and monitor progress -CreateAndMonitorJob $dependencyUris \ No newline at end of file + +$pollingInternavalInSeconds = 60*3 + +$headers = @{ + "SpringfieldApiToken" = $apiToken + "Content-Type" ="application/json" + } + +$osImages = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/osimages" -Headers $headers -Verbose + +Write-Host "Creating a job" +$jobInfo = Invoke-RestMethod -Method POST -Uri "$springfieldUri/api/accounts/$accountId/jobs?osImageId=$($osImages[0].Id)" -Headers $headers -Verbose + +$jobId = $jobInfo.Id +Write-Host "job $jobId created" + +while (-not $jobInfo.IsPreparationVMReady) { + Write-Host "Waiting for the preparation vm to be ready" + Start-Sleep -Seconds $pollingInternavalInSeconds + $jobInfo = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose +} + +Write-Host "Retrieving the machine name" +$machineName = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId/customermachine" -Headers $headers -Verbose +Write-Host "Machine name $machineName retrieved" + +# The command to execute on the job preparation machine +$executionCommand = "powershell.exe -ExecutionPolicy Unrestricted -Command `".\UnzipAndRun.ps1 -zipFile $sampleName.zip -scriptToRun install.ps1 -outputDir 'c:\$sampleName'`"" + +$commandParams = @{ + "command" = $executionCommand + "dependencyUris" = $dependencyUris +} | ConvertTo-Json + +Write-Host "Submitting command for execution $commandParams" +$commandInfo = Invoke-RestMethod -Method POST -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId/machines/$machineName/command" -Headers $headers -Body $commandParams -ContentType 'application/json' -Verbose + +while ($commandInfo.ExecutionState.IsPendingState) { + Write-Host "Waiting for the command to finish executing" + Start-Sleep -Seconds $pollingInternavalInSeconds + $commandInfo = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId/machines/$machineName/command/$($commandInfo.CommandId)" -Headers $headers -Verbose +} + +if ($commandInfo.ExecutionState.IsErrorState) { + throw "Error during execution of custom command : $($commandInfo.ExecutionState.GetError)" +} + +Write-Host "Monitoring command job status until fuzzing or error" +while (-not $jobInfo.IsFuzzing) { + Write-Host "Waiting for the job to start fuzzing" + Start-Sleep -Seconds $pollingInternavalInSeconds + $jobInfo = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose +} + +Write-Host "Poll until we get at least one result" +$results = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId/results" -Headers $headers -Verbose + +while ($results.Count -eq 0){ + Start-Sleep -Seconds $pollingInternavalInSeconds + $results = Invoke-RestMethod -Method GET -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId/results" -Headers $headers -Verbose +} + +Write "Got $($results.Count) results $results" +Write-Host "Deleting the job" + +Invoke-RestMethod -Method DELETE -Uri "$springfieldUri/api/accounts/$accountId/jobs/$jobId" -Headers $headers -Verbose diff --git a/Powershell/UnzipAndRun.ps1 b/Powershell/UnzipAndRun.ps1 index 5dce115..f4b326c 100644 --- a/Powershell/UnzipAndRun.ps1 +++ b/Powershell/UnzipAndRun.ps1 @@ -1,26 +1,28 @@ #.SYNOPSIS # Unpack a .zip file to the spefied target and start # the specified powershell script from the package -# #.PARAMETER zipFile # filename of the zip archive #.PARAMETER outputDir -# target directory where to unzip the archive (optional, by default unzip to the system temp directory) +# target directory where to unzip the archive #.PARAMETER scripToRun # command to run once the package has been extracted. Expressed as relative to outputDir. #.PARAMETER scriptParameters # parameters to pass to the script -# #.EXAMPLE -# & ./UnzipAndRun.ps1 -zipFile sftemplatetools-2015-10-22.zip -scriptToRun SetupTemplateVm.ps1 -scriptParameters '-skipSysprep -unattend' -# +# & ./UnzipAndRun.ps1 -zipFile sftemplatetools-2015-10-22.zip -scriptToRun SetupTemplateVm.ps1 -outputDir c:\test -scriptParameters '-skipSysprep -unattend' param( [Parameter(Mandatory=$true)] $zipfile, + + [Parameter(Mandatory=$true)] $outputDir, + + [Parameter(Mandatory=$true)] $scriptToRun, + $scriptParameters -) +) $ErrorActionPreference='stop' @@ -30,11 +32,6 @@ $thisDir = [System.IO.Path]::GetDirectoryName($thisScript) $zipFilePath = Join-Path $thisDir $zipfile -if(-not $outputDir) { - $fileName = [System.IO.Path]::GetFileNameWithoutExtension($zipFilePath) - $outputDir = "$($Env:ProgramData)\Springfield\setup\$fileName" -} - if(Test-Path $outputDir) { rm -force -Recurse $outputDir } @@ -47,8 +44,4 @@ rm $zipFilePath rm $thisScript $scriptToRunFullPath = Join-Path $outputDir $scriptToRun -try { - Invoke-Expression "$scriptToRunFullPath $scriptParameters" -} catch { - throw "Error while running script [$scriptToRunFullPath $scriptParameters]: $_" -} \ No newline at end of file +Invoke-Expression "$scriptToRunFullPath $scriptParameters" diff --git a/README.md b/README.md index edae5cb..ce3d699 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ Calling the Powershell sample: -accountId ` -apiToken ` -subscriptionId ` - -resourceGroup ` -storageAccountName ` -storageAccountKey ` -testFileFolder `