Monday, May 19, 2014

Modifying MAC properties with PowerShell

Laziness is the demise of Red Team engagements. Whether it is writing PsExec to a user's desktop or writing other arbitrary binaries to disk, not being careful can lead to being discovered. One of the competitors of this year's National CCDC mentioned to me that his team focused on discovering files created during the competition. If we were all being careful, that shouldn't work. Linux has the ability to modify file attributes with the "Touch" utility. Meterpreter has TimeStomp which works on Windows and makes it easy to blend your files with files around it by modifying the MACE attributes.

After a request to add the capability to PowerSploit, I wanted to figure out how to do it (I do prefer avoiding writing anything to disk, but there are times when it is unavoidable). I always thought that TimeStomp was black magic, but then I noticed the capability in Cobalt Strike's Beacon. I asked Raphael and he pointed me to a well-documented part of the Windows API. So naturally I headed over to pinvoke.net to check out the C# sample. It didn't take long to have a working function, but I got curious and found a .Net class to simplify the code. Armed with two working functions, I boarded the plane after ShowMeCon and wondered if it were possible to accomplish the task in a more "PowerShelly" (technical term) way.

Lets explore with Get-Member:


Wow, we can set the modified, accessed and created properties with Get-Item. That means we can simply run:

PowerShell.exe -com {$file=(gi c:\demo\test.txt);$date='01/03/2006 12:12 pm';$file.LastWriteTime=$date;$file.LastAccessTime=$date;$file.CreationTime=$date}
view raw gistfile1.ps1 hosted with ❤ by GitHub

Nothing novel, but cool nonetheless. Some people would prefer a more "Touch" like capability, so I wrapped it all up in a function called Set-MacAttributes which will be added to PowerSploit soon:

function Set-MacAttribute {
<#
.SYNOPSIS
Sets the modified, accessed and created (Mac) attributes for a file based on another file or input.
PowerSploit Function: Set-MacAttribute
Author: Chris Campbell (@obscuresec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
Version: 1.0.0
.DESCRIPTION
Set-MacAttribute sets one or more Mac attributes and returns the new attribute values of the file.
.EXAMPLE
PS C:\> Set-MacAttribute -FilePath c:\test\newfile -OldFilePath c:\test\oldfile
.EXAMPLE
PS C:\> Set-MacAttribute -FilePath c:\demo\test.xt -All "01/03/2006 12:12 pm"
.EXAMPLE
PS C:\> Set-MacAttribute -FilePath c:\demo\test.txt -Modified "01/03/2006 12:12 pm" -Accessed "01/03/2006 12:11 pm" -Created "01/03/2006 12:10 pm"
.LINK
http://www.obscuresec.com/2014/05/touch.html
#>
[CmdletBinding(DefaultParameterSetName = 'Touch')]
Param (
[Parameter(Position = 1,Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[String]
$FilePath,
[Parameter(ParameterSetName = 'Touch')]
[ValidateNotNullOrEmpty()]
[String]
$OldFilePath,
[Parameter(ParameterSetName = 'Individual')]
[DateTime]
$Modified,
[Parameter(ParameterSetName = 'Individual')]
[DateTime]
$Accessed,
[Parameter(ParameterSetName = 'Individual')]
[DateTime]
$Created,
[Parameter(ParameterSetName = 'All')]
[DateTime]
$AllMacAttributes
)
Set-StrictMode -Version 2.0
#Helper function that returns an object with the MAC attributes of a file.
function Get-MacAttribute {
param($OldFileName)
if (!(Test-Path $OldFileName)){Throw "File Not Found"}
$FileInfoObject = (Get-Item $OldFileName)
$ObjectProperties = @{'Modified' = ($FileInfoObject.LastWriteTime);
'Accessed' = ($FileInfoObject.LastAccessTime);
'Created' = ($FileInfoObject.CreationTime)};
$ResultObject = New-Object -TypeName PSObject -Property $ObjectProperties
Return $ResultObject
}
#test and set variables
if (!(Test-Path $FilePath)){Throw "$FilePath not found"}
$FileInfoObject = (Get-Item $FilePath)
if ($PSBoundParameters['AllMacAttributes']){
$Modified = $AllMacAttributes
$Accessed = $AllMacAttributes
$Created = $AllMacAttributes
}
if ($PSBoundParameters['OldFilePath']){
if (!(Test-Path $OldFilePath)){Write-Error "$OldFilePath not found."}
$CopyFileMac = (Get-MacAttribute $OldFilePath)
$Modified = $CopyFileMac.Modified
$Accessed = $CopyFileMac.Accessed
$Created = $CopyFileMac.Created
}
if ($Modified) {$FileInfoObject.LastWriteTime = $Modified}
if ($Accessed) {$FileInfoObject.LastAccessTime = $Accessed}
if ($Created) {$FileInfoObject.CreationTime = $Created}
Return (Get-MacAttribute $FilePath)
}
view raw gistfile1.ps1 hosted with ❤ by GitHub


I think its a prime example of why you should start by exploring cmdlets, then check out .Net and finally the API. It can save you a lot of time when you are building PowerShell tools. Obviously this won't stand up to forensic scrutiny like TimeStomp will, but it will definitely serve the purpose of hiding files in plain sight.

-Chris



Sunday, May 18, 2014

Dirty PowerShell WebServer

I was recently asked why there wasn't a PowerShell entry in this great list of web-server one-liners. Of course it is possible, but not as easy as with other scripting languages. Web-servers are dangerous in the wrong hands, but testers use them all the time (not always safely). I have seen people upload utilities like Mongoose to accomplish serving static files, but it can  be accomplished with PowerShell and the .Net httplistener class. The goal of the one-liners was to serve static files from the present working directory on port 8000. Since we know the goal is to have a small and dirty script, we can skip error-handling and use aliases:

 
$Hso = New-Object Net.HttpListener
$Hso.Prefixes.Add("http://+:8000/")
$Hso.Start()
While ($Hso.IsListening) {
$HC = $Hso.GetContext()
$HRes = $HC.Response
$HRes.Headers.Add("Content-Type","text/plain")
$Buf = [Text.Encoding]::UTF8.GetBytes((GC (Join-Path $Pwd ($HC.Request).RawUrl)))
$HRes.ContentLength64 = $Buf.Length
$HRes.OutputStream.Write($Buf,0,$Buf.Length)
$HRes.Close()
}
$Hso.Stop()

So that wasn't painful, but not too helpful. How did we get here? Lets pipe the created object to Get-Member and explore the relevant properties and methods.


Now that we can put together a basic usage of the httplistener object, lets explore some of the properties of the request. Specifically, we need to know what part of the request we can use to find the name of the file. We can use the debugger that comes with the ISE to catch our loop and use the console to enumerate each of the properties until we find the one we want:


Now that we have everything put together, we just need roll it into a one-liner and encode it:



Finally, we have our encoded one-liner which will statically serve files from the present working directory.


We will need to have admin rights to grab a port, but otherwise it is pretty handy.


Thanks for reading about the basics of the httplistener class, maybe you will find it useful.

-Chris

Wednesday, April 30, 2014

Custom Properties and Descriptions in AD

One of the first things I like to do when I land on a domain-joined machine is enumerate the domain. Sometimes I do this even before attempting to privilege escalate. Sometimes a few LDAP queries is all you need to accomplish your goal.

During the planning phase of an engagement, I try to ascertain at least three data points that the organization feels are critical to their business and would be devastating if it fell into the wrong hands. That data is my ultimate goal and sometimes that data is stored in the database known as Active Directory (AD). I don't know if there is a single reason why organizations choose to store sensitive information in AD, but I have found it several times. PowerShell v2 introduced a type accelerator which makes enumerating AD quite simple and allows us to use PowerShell to manipulate the results without diving to deep into LDAP queries:

$LdapFilter = #Query Goes Here
([adsisearcher]"$LdapFilter").Findall()
view raw gistfile1.ps1 hosted with ❤ by GitHub
A simple way to enumerate all domain users from any user or machine account (this works great in situations where the "net" utility is deleted or restricted and returns much more digestible output):

([adsisearcher]"objectCategory=User").Findall() | ForEach {$_.properties.cn}
view raw gistfile1.ps1 hosted with ❤ by GitHub
Additionally, we can wrap that into a simple one-liner to be run from cmd.exe (or your favorite shell). For example, if we wanted to enumerate all machines in the domain:

powershell.exe -com '([adsisearcher]'objectCategory=Computer').Findall() | ForEach {$_.properties.cn}'
view raw gistfile1.ps1 hosted with ❤ by GitHub
Unfortunately, that pipe ("|") is going to give us problems. We can easily encode it from within PowerShell:

(cmd /c echo {([adsisearcher]'objectCategory=Computer').Findall() | ForEach {$_.properties.cn}}).split(' ')[1]
view raw gistfile1.ps1 hosted with ❤ by GitHub
Now we can run our query:

powershell.exe -enc KABbAGEAZABzAGkAcwBlAGEAcgBjAGgAZQByAF0AJwBvAGIAagBlAGMAdABDAGEAdABlAGcAbwByAHkAPQBDAG8AbQBwAHUAdABlAHIAJwApAC4ARgBpAG4AZABhAGwAbAAoACkAIAB8ACAARgBvAHIARQBhAGMAaAAgAHsAJABfAC4AcAByAG8AcABlAHIAdABpAGUAcwAuAGMAbgB9AA==
view raw gistfile1.ps1 hosted with ❤ by GitHub
Nothing earth-shattering there, but where it gets interesting is if you discover customer properties that the organization has added to the account objects. To find that, we simply enumerate the 'PropertyNames' of any of the accounts returned in the array:

powershell.exe -com "((([adsisearcher]"objectCategory=User").Findall())[0].properties).PropertyNames"
view raw gistfile1.ps1 hosted with ❤ by GitHub


Being able to dump the social security numbers of every employee or user is obviously a critical finding, but sometimes the other data can come in handy for further social engineering attacks or to demonstrate the risk of single link clicked. I have found employee IDs, cell phone numbers, supervisor information, number of disciplinary actions, which user's internet activity was being monitored, hourly rate and salary information. In one case, the information available in AD was what was needed to request VPN credentials and remotely reset their password.

Since most administrators interact with AD with a MMC snapin, they mistakingly believe that custom fields can't be viewed by other users. Fortunately, they can easily adjust the permissions on those properties to only be viewed by members of specific groups. At least then an attacker would have to privilege escalate or laterally compromise a member of one of the privileged groups. Even then, I wouldn't recommend storing sensitive information within AD.

One of the default properties that I like to check is the description field. Most of the time there are just notes about the account, but other times there are passwords. Passwords are obviously valuable, but the notes can be pretty valuable as well. For example, a trend I see in many high-security enterprises is to obfuscate user account common names. This protects from account guessing attacks from open-source information, but is little protection from any legitimate or illegitimate user on the domain if the real name of the user is used in the comment field. To enumerate properties:



It is also worthwhile to enumerate the properties of the computer accounts as well.

-Chris


Monday, March 31, 2014

Retrieving NTDS.dit without a Shell on the DC

It has been increasingly common for organizations to prevent external or outbound connections from their domain controllers. I have seen some use the Windows Firewall, others use non-routable IP addresses and others have installed third-party software to prevent any type of remote access. These are all recommended practices, but some security administrators wrongfully assume that their domain hashes are safe simply because they believe that it is impossible to get a meterpreter shell on any of their DCs.

Sometimes you really have to work to gain Domain Admin privileges, and other times you don't. On more than one occasion (read 2) I have been able to guess a webserver password for Symantec NetBackup servers. The first time, there didn't appear to be a obvious way of converting that access to code execution, but one of the features of the product is the ability to generate custom reports. The report generation utility can be used to generate custom database queries against a Sybase database. Sybase typically runs as SYSTEM and can be used to run commands. Combine that with PowerShell and achieving a memory-resident shell, regardless of AV product,was trivial with PowerSploit.

Armed with a fully-privileged shell on a seldom used backup server, I was in business. First lets look at the tokens on the box:



It looks like the service account is a domain admin and we can impersonate it by migrating into the netbackup service. Now its time to get the hashes and then start going after what really matters - the data. Unfortunately, I could not get the DC to initiate an outbound connection of any kind. Some combination of configuration and/or security products were preventing me from getting a shell on the DC. Without really knowing what is blocking our shells, we needed a safe way to dump the domain hashes. One method that is almost always AV-safe is to use built-in tools. There are write-ups on one method of copying the NTDS.dit, but I prefer a simpler one:


This technique relies on the Ntdsutil binary which ships with Server 2008, but may be found on 2003 servers as well. Next, we can do something similar to obtain the SYSTEM file and download them both with Meterpreter:


Armed with the database and SYSTEM files, you can continue with extracting the hashes offline. May not work in all situations, but it is another way to dump the domain hashes quickly once gaining "domain admin" rights.

-Chris

Sunday, February 23, 2014

The $env:PATH Less Traveled: Subverting Trust with 3rd-Party Applications

Some of easiest and most effective privilege escalation attacks don't rely on vulnerabilities, but rather on misconfigurations. One common misconfiguration that is often overlooked by testers involves the Windows environment variable PATH. The PATH is considered a trusted part of the operating system. The PATH is consulted by nearly every application on a running system and one rogue entry is all that is needed to take administrative control of a system.

What happens when a 3rd-party application writes its installation directory to the PATH? If the NTFS permissions of the directory aren't properly applied, then that software has a clear vulnerability. But what if they only recommend that YOU place their insecure directories in the PATH? No vulnerability to report except the one that is now on your system. Generally, an attack against Windows that leverages a 3rd-party application isn't considered a vulnerability according to their "10 Immutable Laws of Security". So its not Microsoft's fault and its not the vendor's fault.

If at this point you are thinking "Oh great, another DLL-preloading write-up...", please hold on. Although that is still a very common and valid attack, this is slightly different. Lets see what happens when the Python installation meets a feature (or flaw) of PowerShell v3 which allows us to potentially privilege escalate in a multi-user environment.

First, lets install Python on a Windows 7 machine with appropriate WMF installed.

Now we can follow the recommendation to add Python to the PATH environment thereby making our machine more vulnerable to privilege escalation attacks. To be clear, we are already vulnerable due to default permissions of the installer. Any user can replace a binary and wait for another user or process to execute python. I have successfully attacked this scenario before in an engagement, but it relies on the binary being used by a more privileged account. It could also introduce other DLL preloading opportunities to binaries that wouldn't otherwise have them (its been a fun challenge to figure out how to reliably find these conditions with a script). Those binaries could be services which could be leveraged with a simple file write and reboot without the admin interaction requirement.



Now as a low-privilege user we can write anything we want to the 'C:\Python' directory. We want to elevate our privileges on a modern Windows system and have exhausted other methods. Here is where the bug in PowerShell v3 becomes useful. Anytime you interact with the PowerShell console, either with enter or tab, the PATH is searched for the existence of 'PSConsoleHostReadline'. You can read more about why that feature was introduced here. Here is what it looks like in Process Monitor:



Now we need to create a simple function and drop a PSConsoleHostReadline.CMD (or any of the extensions in the screenshot above) into any of the searched Python directories.


What command should we run? My first thought was to use the one described here. But the problem is that once PowerShell is run, it will attempt to execute the file each time a line is entered. That would be problematic and could potentially put it in a loop. It can be done, but for simplicity lets take our limited user account and add it to the administrators group. Once an administrator invokes PowerShell.exe on the box:


Escalation achieved.

So in order for this particular attack to work, it would require:

     1. An application that installs with insecure permissions (such as the default at 'C:\').
     2. That application's path being added to the PATH either by the install or after.
     3. PowerShell being at Version 3 (default on Windows 8).
     4. A privileged account executing PowerShell on the box.

Maybe this scenario is a bit far-fetched, but let me assure you that there are lots of applications that automatically add themselves to PATH and allow "Authenticated Users" to write to their directory. To see how common this and other permissions-based vulnerabilities are, I tested the new functions against over 1000 common Windows installations. The result has me buried in the disclosure process with several projects. My hope is to reference this blog post to speed things along enough to present my findings (with references to the vulnerable software) at a conference or two this Summer and Fall. I also look forward to polishing the scripts up so they can be integrated with PowerSploit this Spring.

Lastly, this post came about from a series of discussions with Matt about the new privilege escalation functions that will be added to PowerSploit and the about the PATH. He discovered the potential for misuse of the feature in PowerShell and reported it to Microsoft a year ago (it was subsequently removed from version 4 of PowerShell). He also brought up a few other potential attack vectors like PowerShell profiles and modules. After all, this is just one example of how applications that subvert the trusted PATH can be exploited.

-Chris



Monday, February 10, 2014

Resolving Hostnames with PowerShell and the Pipeline

Thanks to Matt, PowerSploit has had a function to resolve hostnames to IP addresses for a while. The Invoke-ReverseDnsLookup utility is useful in mapping a domain from inside or out. Often, organizations use overly-descriptive names which can help an attacker narrow down their targets during initial recon and again once they have a foothold on the inside of a network. If you haven't used it, you should check it out.

Recently, we added support for two things to the function which I found helpful on a recent engagement. Both are simple enhancements that come with the PowerShell language that you may want to implement in your tools.

The first is the use of the Write-Verbose cmdlet which is a Common Parameter. That means it comes free when you declare your parameters with "[CmdletBinding()]" and then can be called by adding the "-verbose" switch when the function is called. Optionally, it can be enabled by changing $VerbosePreference, but by default it doesn't show anything. In the case of Invoke-ReverseDnsLookup, I added it to the function to be able to see what IP address it was currently trying to resolve. Since verbose statements are written to the console and not the output pipeline, you can use any of the "out-*" without it being cluttered with messages.


The next feature of PowerShell that we added is support for input from the pipeline. Pipeline input allows functions to be chained together and allows developers to focus on doing one thing. Where input is coming from and how the output is parsed or stored should be handled by the user. For example, I had a text file of several different network ranges and IP addresses that I wanted to be able to pass to Invoke-ReverseDnsLookup, but it didn't support it. Fortunately, it is simple to add support to your tools. The first thing you need to do is decide what logic (if any) only needs to happen once at the beginning or at the end of the script. In our case, Matt wrote a function to break out and validate CIDR ranges into individual addresses. We don't need to declare that function for every IP address, so we will create a BEGIN script block:


The only required script block is PROCESS. That is the part that will do the work on each object coming down the pipeline. You can see the PROCESS block above and how the current IP address in the pipeline is reference with the pipeline variable ($_). Once the PROCESS block is done, the optional END block does any post-processing for the function.



Certainly nothing ground-breaking here, but I thought I would share some neat features of PowerShell and how they can be applied to your tools. It may give you some insight into the "why" behind some of the functions in PowerSploit. Thank you for reading.