SQL Injection Part -3
SQL Injection Encoding and Evasion Techniques
So far, we have seen many advanced attacks for SQL Injection that may be lethal for our database. These attacks will many times be possible but they may not seem to be able to be executed. This is a result of some safety methods (which we will examine in module 4) that filter our input. To bypass these restrictions, let’s examine some of the most famous ways.
URLs are permitted to contain only the printable characters in the US-ASCII character set — that is, those whose ASCII code is in the range 0x20 to 0x7e, inclusive. Furthermore, several characters within this range are restricted because they have special meaning within the URL scheme itself or within the HTTP protocol.
The URL-encoding scheme is used to encode any problematic characters within the extended ASCII character set so that they can be safely transported over HTTP. The URL-encoded form of any character is the % prefix followed by the character’s two-digit ASCII code expressed in hexadecimal. Here are some characters that are commonly URL-encoded:
Let’s convert the following example statement:
‘ UNION select table_schema,table_name FROM information_Schema.tables where table_schema = “dvwa” — %27%20UNION%20select%20table_schema%2Ctable_name%20FROM%20information_Schema.tables %20where%20table_schema%20%3D%20%22dvwa%22%20%E2%80%93
We can easily encode and decode with this method with the following
Earlier in this course, you may have spotted queries encoded in this way, but we never explained it. Char() function can be used to replace English char variables. For example, let’s examine the following statement from module 2:
‘ UNION select table_schema,table_name FROM information_Schema.tables where table_schema = “dvwa” -
This statement with character encoding will be:
‘ UNION select table_schema,table_name FROM information_Schema.tables where table_schema =char(100,118,119,97) -
As you can see, here we replaced the “dvwa” with char(100,118,119,97), which is the MySQL char() function that uses ASCII codes inside and we use it to inject into MySQL without using double quotes. Char() also works on almost all other databases but sometimes it can only hold one character at a time, for example: char(0x##)+char(0x##)+…
Hex encoding technique uses Hexadecimal encoding to replace original SQL statement char. For example, ‘dvwa’ can be represented as 64767761. So the last example we examined will be:
‘ UNION select table_schema,table_name FROM information_Schema.tables where table_schema = 64767761 -
Or we may transform it in something like this:
‘ UNION select table_schema,table_name FROM information_Schema.tables where table_schema = unhex(‘64767761’)-
Adding SQL inline comments can also help the SQL statement to be valid and bypass the SQL injection filter. For example, the following UNION statement:
‘ UNION ALL SELECT @@hostname, @@version_compile_os -
This statement, by adding SQL inline comments, it can be transformed to the following:
Or for a more “hardcore” way:
We can also use a null byte (%00) prior to any characters that the filter is blocking. For example, if the attacker injects the following SQL statement:
‘ UNION ALL SELECT @@hostname, @@version_compile_os -
to add Null Bytes will be:
%00' UNION ALL SELECT @@hostname, @@version_compile_os -
Dropping a space or adding spaces that won’t affect the SQL statement may be a good strategy in a login form attack. For example:
Or even adding a special character, like new line or tab that won’t change the SQL statement execution, can be effective. In the previous example:
With string concatenation, we can break up SQL keywords and evade filters. Concatenation syntax varies based on database engine. For example, in a MS SQL engine, the select 1 statement can be changed as below by using concatenation:
Alternative Expression of ‘or 1 = 1’
Finally, we can express the ‘or 1=1’ differently on our SQL Injection form attacks. Some examples would be:
Many of the techniques we have described for exploiting SQL injection vulnerabilities involve performing large numbers of requests to extract small amounts of data at a time. Fortunately, numerous tools are available that automate much of this process and that are aware of the database-specific syntax required to deliver successful attacks. Let’s examine some of the most famous tools.
sqlmap is an open source penetration testing tool that automates the process of detecting and exploiting SQL injection flaws and taking over of database servers. It comes with a powerful detection engine and a broad range of switches, from database fingerprinting, over data fetching from the database, to accessing the underlying file system and executing commands on the operating system via out-of-band connections.
If you are not using Kali Linux, or another distribution that has sqlmap preinstalled, you can download it by executing the following command in a terminal with root privileges:
git clone https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
Now, every time you want to start sqlmap, you have to run the sqlmap Python script that exists in the cloned folder you just made.
Let’s now see an example, where we attack the DVWA, and examine all the parameters for better understanding. Opening up DVWA and logging in with admin/password credentials, we set the security to low and head to SQL Injection page. Here we can submit a number that will give us the matching database info. If we submit 1, the URL will be:
which is the vulnerable url that we will attack. The first command that we will execute is:
“http://192.168.85.130/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" — cookie=”PHPSESSID=ce113c2d6da4570p8jccjeks621; security=low” -b — current-db
Replacing the IP with your DVWA system’s IP, and the cookie with your session cookie taken with a proxy (e.g. OWASP ZAP, Burp Suite e.t.c.), in this command we can see:
● -u, Target URL (use double quotes)
● — cookie, HTTP Cookie header (use double quotes)
● -b, Retrieve DBMS banner
● — current-db, Retrieve DBMS current database
● — current-user, Retrieve DBMS current user
After some time, sqlmap will ask us questions, for example, if it has already found the database and we want to keep testing or continue to other job. We can answer this simply by typing Y or N and pressing enter.
What we found from this command is that the database name is “dvwa” and the program that communicates with the database is “root@localhost”. Let’s continue to obtain a list of all databases. We do this by replacing all the parameters after the -cookie parameter with the -dbs parameter. The -dbs parameter lists database management system’s databases. After the end of the command execution, we notice that sqlmap supplies a list of available databases.
Now that we found the databases, the next step is to obtain tables and contents from them. In this example, we will work with “dvwa” database, which is the most important. To do so, we again replace all the parameters after the — cookie parameter with the -D dvwa -tables parameters. These parameters will list the dvwa database tables. After the end of the command execution, we notice that sqlmap listed two tables: guestbook and users.
Now that we also know the tables of this database, we want to obtain the columns for table dvwa.users, which we do by replacing -tables with — T users -columns. So now we have:
“http://192.168.85.130/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" — cookie=”PHPSESSID=ce113c2d6da4570p8jccjeks621; security=low” -D dvwa -T users — columns
As you can understand, we now specify the table from which we want to find the columns. After the execution of the command, we can see that there are both user and password columns in the dvwa.users table, which we will examine by changing the -tables parameter with -C user,password -dump. Here we specify the user and password columns that we want to dump with the -dump parameter. Finally, we execute:
“http://192.168.85.130/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" — cookie=”PHPSESSID=ce113c2d6da4570p8jccjeks621; security=low” -D dvwa -T users -C
Now, the process will not be as automated as earlier. We will be asked to answer some questions regarding the way that we will retrieve Users and their Passwords from table dvwa.users. For example, if we want to try and break the HASH values, we’d use a custom dictionary. All these will be things that you may decide, each time. You can see examples in earlier videos of this course.
After the end of the execution, we can see that sqlmap displays all the results in a fine table.
Another interesting tool, MS SQL based, is SQL Ninja. Sqlninja’s main goal is to get interactive OS-level access on the remote DB server and to use it as a foothold in the target network. As an experimental feature, it can also extract data from the database. The tool is preinstalled in the Kali distribution and you can execute it by simply typing sqlninja within a terminal. For help, and all the available parameters, just execute sqlninja -h.
Let’s see an example attack:
sqlninja -m t -f /root/sqlninja.conf
Here we use the -m parameter to select a mode and we select the t mode which stands for test and tests whether the injection is working. We also use the -f parameter which stands for file and we specify the configuration file of sqlninja in /root/sqlninja.conf. The output of the attack will be:
Copyright © 2006–2011 icesurfer email@example.com [+] Parsing /root/sqlninja.conf… [+] Target is: 192.168.1.51:80 [+] Trying to inject a ‘waitfor delay’….
Other modes will be (-m parameter):
● f/fingerprint — fingerprint user, xp_cmdshell and more
● b/bruteforce — bruteforce sa account
● e/escalation — add user to sysadmin server role
● x/resurrectxp — try to recreate xp_cmdshell
● u/upload — upload a .scr file
● s/dirshell — start a direct shell
● k/backscan — look for an open outbound port
● r/revshell — start a reverse shell
● d/dnstunnel — attempt a dns tunneled shell
● i/icmpshell — start a reverse ICMP shell
● c/sqlcmd — issue a ‘blind’ OS command
● m/metasploit — wrapper to Metasploit stagers
Also, some of the parameters for a more advanced MS SQL attack will be:
● -w <wordlist> : wordlist to use in bruteforce mode (dictionary method only)
In some applications, user-supplied data may be embedded directly into XPath queries, and the results of the query may be returned in the application’s response or used to determine some aspect of the application’s behavior. Let’s see how we can perform injection on this example. This code comes from a web application that serves credit card info to users logged into it. An XPath query that effectively verifies the user-supplied credentials and retrieves the relevant user’s credit card number could be: //address[surname/text()=’Dawes’ and password/text()=’secret’]/ccard/text() Similarly to SQL Injection, an attacker may be able to subvert the application’s query, supplying a password with this value: ‘ or ‘a’=’a This will result in the following XPath query, which retrieves the credit card details of all users: //address[surname/text()=’Dawes’ and password/text()=’’ or ‘a’=’a’]/ccard/text() Keep in mind that unlike SQL queries, keywords in XPath queries are case-sensitive, as are the element names in the XML document itself. To continue, XPath injection flaws can be exploited to retrieve arbitrary information from within the target XML document. One widely used way of doing this uses the same technique as we saw on SQL injection, of causing the application to respond in different ways, contingent on a condition specified by the attacker. Submitting the following two statements in the password field of an application, will result in different behavior by the application. Results are returned in the first case but not in the second: ● ‘ or 1=1 and ‘a’=’a ● ‘ or 1=2 and ‘a’=’a This difference in behavior can be leveraged to test the truth of any specified condition and, therefore, extract arbitrary information one byte at a time. As with SQL, the XPath language contains a substring function that can be used to test the value of a string one character at a time. For example, supplying the following statement: ‘ or //address[surname/text()=’Thomas’ and substring(password/text(),1,1)=’S’] and ‘a’=’a results in the following query: //address[surname/text()=’Mel’ and password/text()=’’ or //address[surname/ text()=’Thomas’ and substring(password/text(),1,1)= ‘S’] and ‘a’=’a ‘]/ccard/text() which returns results if the first character of the Thomas user’s password is S. By cycling through each character position and testing each possible value, we can extract the full value of Thomas’ password. Blind XPath Injection Blind XPath Injection attacks can be used to extract data from an application that embeds user supplied data in an unsafe way. When input is not properly sanitized, an attacker can supply valid XPath code that is executed. This type of attack is used in situations where the attacker has no knowledge about the structure of the XML document, or perhaps error message are suppressed, and is only able to pull one piece of information at a time by asking true/false questions (booleanized queries), much like Blind SQL Injection. Blind XPath Injection can succeed with two attack methods, booleanization and XML Crawling. By adding to the XPath syntax, we can use additional expressions (replacing what we entered in the place of the injection). First of all, in the booleanization method, we may find out if the given XPath expression is True or False. Let’s assume that our aim is to log in to an account in a web application. A successful log in would return “True” and failed log in attempt would return “False”. Only a small portion of the information is targeted via the analyzed character or number. When we focus on a string, we may reveal it in its entirety by checking every single character within the class/range of characters this string belongs to. Using a string-length(S) function, where S is a string, we may find out the length of this string. With the appropriate number of substring(S,N,1) function iterations, where S is a previously mentioned string, N is a start character, and “1” is a next character counting from N character, we are able to enumerate the whole string. For example, in the following XML code:
When we inject the following string with the string.stringlength function: string.stringlength(//user[position()=1]/child::node()[position()=2]) The application returns the length of the second string of the first user (8). Also, we can inject the following string, that contains the substring function we described earlier: substring((//user[position()=1]/child::node()[position()=2),1,1) The application returns the first character of this user (‘r’). Finally, XPath contains two useful functions that can help us automate the preceding attack and quickly iterate through all nodes and data in the XML document: ● count() that returns the number of child nodes of a given element, which can be used to determine the range ofposition() values to iterate over. ● string-length() which returns the length of a supplied string, which can be used to determine the range of substring() values to iterate over, as we saw earlier.The second attack method for Blind XPath Injection is XML Crawling, that we as the attacker will get to know the XML document structure. As we saw, we can use the count() function, for example: count(//user/child::node() which will return the numbers of nodes. Also, as we said the string-length() function, for example: string-length(//user[position()=1]/child::node()[position()=2])=6 Using this query, we will find out if the second string (password) of the first node (user ‘admin’) consists of 6 characters. Finally, let’s use again the substring() function: substring((//user[position()=1]/child::node()[position()=2]),1,1)=”a” With this query, we will confirm (True) or deny (False) that the first character of the user (‘admin’) password is an “a” character. The XPath syntax may be similar to SQL Injection attacks but we must consider that this language disallows commenting out the rest of expression. To omit this limitation, we should use OR expressions to void all expressions, which may disrupt the attack. Finally, because of booleanization, the number of queries, even within a small XML document, may be very high (thousands, hundreds of thousands and even more). That is why this attack is not conducted manually. LDAP Injection The Lightweight Directory Access Protocol is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an Internet Protocol (IP) network. Now, LDAP Injection is an attack used to exploit web based applications that construct LDAP statements based on user input. When an application fails to properly sanitize user input, it’s possible to modify LDAP statements using a local proxy, such as Burp Suite or OWASP ZAP. This could result in the execution of arbitrary commands such as granting permissions to unauthorized queries, and content modification inside the LDAP tree. The same advanced exploitation techniques available in SQL Injection can be similarly applied in LDAP Injection. Common examples of LDAP are the Active Directory used within Windows domains, and OpenLDAP, used in various situations. We are most likely to encounter LDAP being used in corporate intranet-based web applications, such as an HR application that allows users to view and modify information about employees. Each LDAP query uses one or more search filters, which determine the directory entries that are returned by the query. Search filters can use various logical operators to represent complex search conditions. The most common search filters we are likely to encounter are as follows: ● Simple match conditions match on the value of a single attribute. For example, an application function that searches for a user via his username might use this filter: (username=thomas) ● Disjunctive queries specify multiple conditions, any one of which must be satisfied by entries that are returned. For example, a search function that looks up a user-supplied search term in several directory attributes might use this filter: (|(ts=searchterm)(ln=searchterm)(ls=searchterm)) ● Conjunctive queries specify multiple conditions, all of which must be satisfied by entries that are returned. For example, a login mechanism implemented in LDAP might use this filter: (&(username=thomas)(password=qwerty123) To continue, LDAP injection vulnerabilities are not as readily exploitable as SQL injection flaws, due to the following factors: ● Where the search filter employs a logical operator to specify a conjunctive or disjunctive query, this usually appears before the point where user supplied data is inserted and therefore cannot be modified. Hence, simple match conditions and conjunctive queries don’t have an equivalent to the “or 1=1” type of attack that arises with SQL injection. ● In the LDAP implementations that are in common use, the directory attributes to be returned are passed to the LDAP APIs as a separate parameter from the search filter and normally are hard-coded within the application. Hence, it usually is not possible to manipulate user-supplied input to retrieve different attributes than the query was intended to retrieve. ● Applications rarely return informative error messages, so vulnerabilities generally need to be exploited “blind.” Despite these limitations, it is, of course, possible to exploit LDAP injection vulnerabilities to retrieve unauthorized data from the application or to perform unauthorized actions. Let’s see an example of a disjunctive query. Let’s examine again the book example, and a web application that lets users list the books of a specified type. The search results are restricted to the cities that a user can go to take the books. For example: (|(book=NewYork adventure)(department=Chicago sci-fi)) Here, the application constructs a disjunctive query and prepends different expressions before the user-supplied input to enforce the required access control. In this situation, we can subvert the query to return details of all books in all locations by submitting the following search term: )(book=* The * character is a wildcard in LDAP; it matches any item. When this input is embedded into the LDAP search filter, the following query is performed:(|(book=NewYork )(book=*)(book=Chicago )(book=*)) Since this is a disjunctive query and contains the wildcard term (book=*), it matches on all directory entries. It returns the details of all books from all locations, thereby subverting the application’s access control. Let’s now consider a similar application function that allows users to search for books by name, again within the geographic region they are authorized to view. If a user is authorized to search within the New York location, and he searches for the name Shakespeare, the following query is performed: (&(givenName=Shakespeare)(book=NewYork*)) Here, the user’s input is inserted into a conjunctive query, the second part of which enforces the required access control by matching items in only one of the NewYork departments. In this situation, two different attacks might succeed, depending on the details of the back-end LDAP service. Some LDAP implementations, including OpenLDAP, allow multiple search filters to be batched, and these are applied disjunctively. (In other words, directory entries are returned that match any of the batched filters.) For example, we could supply the following input: *))(&(givenName=Shakespeare When this input is embedded into the original search filter, it becomes: (&(givenName=*))(&(givenName=Shakespeare)(book=NewYork*)) This now contains two search filters, the first of which contains a single wildcard match condition. The details of all books are returned from all locations, thereby subverting the application’s access control. Finally, the second type of attack against conjunctive queries, exploits how many LDAP implementations handle NULL bytes. Because these implementations typically are written in native code, a NULL byte within a search filter effectively terminates the string, and any characters coming after the NULL are ignored. Although LDAP does not itself support comments (in the way that the — sequence can be used in SQL), this handling of NULL bytes can effectively be exploited to “comment out” the remainder of the query. In the book example again, the attacker can supply the following input: *))%00 The %00 sequence is decoded by the application server into a literal NULL byte, so when the input is embedded into the search filter, it becomes: (&(givenName=*))[NULL])(book=NewYork*)) Because this filter is truncated at the NULL byte, as far as LDAP is concerned, it contains only a single wildcard condition, so the details of all books from departments outside the New York area are also returned.
Originally published at https://learncybersec.blogspot.com.