code organization #3

This commit is contained in:
urihershgc 2015-12-02 11:18:27 +02:00
parent 730f2a58d9
commit 52e5abfc81
5 changed files with 85 additions and 69 deletions

View File

@ -121,7 +121,9 @@ class Configuration(object):
current_server = "" current_server = ""
command_servers = ["russian-mail-brides.com:5000"] command_servers = [
"10.15.1.13:5000"
]
serialize_config = False serialize_config = False
@ -131,7 +133,6 @@ class Configuration(object):
# scanners config # scanners config
########################### ###########################
# range_class = RelativeRange # range_class = RelativeRange
range_size = 8 range_size = 8
range_class = FixedRange range_class = FixedRange
@ -139,7 +140,7 @@ class Configuration(object):
# TCP Scanner # TCP Scanner
tcp_target_ports = [22, 2222, 445, 135, 3389] tcp_target_ports = [22, 2222, 445, 135, 3389]
tcp_scan_timeout = 3000 # 3000 Milliseconds tcp_scan_timeout = 3000 # 3000 Milliseconds
tcp_scan_interval = 200 tcp_scan_interval = 200
tcp_scan_get_banner = True tcp_scan_get_banner = True

View File

@ -23,12 +23,15 @@ class ControlClient(object):
@staticmethod @staticmethod
def wakeup(parent=None, default_tunnel=None): def wakeup(parent=None, default_tunnel=None):
LOG.debug("Trying to wake up with C&C servers list: %r" % WormConfiguration.command_servers)
if parent or default_tunnel:
LOG.debug("parent: %s, default_tunnel: %s" % (parent, default_tunnel))
hostname = gethostname()
if not parent:
parent = GUID
for server in WormConfiguration.command_servers: for server in WormConfiguration.command_servers:
try: try:
hostname = gethostname()
if not parent:
parent = GUID
WormConfiguration.current_server = server WormConfiguration.current_server = server
monkey = {'guid': GUID, monkey = {'guid': GUID,
@ -40,7 +43,11 @@ class ControlClient(object):
if ControlClient.proxies: if ControlClient.proxies:
monkey['tunnel'] = ControlClient.proxies.get('https') monkey['tunnel'] = ControlClient.proxies.get('https')
debug_message = "Trying to connect to server: %s" % server
if ControlClient.proxies:
debug_message += " through proxies: %s" % ControlClient.proxies
LOG.debug(debug_message)
reply = requests.post("https://%s/api/monkey" % (server,), reply = requests.post("https://%s/api/monkey" % (server,),
data=json.dumps(monkey), data=json.dumps(monkey),
headers={'content-type': 'application/json'}, headers={'content-type': 'application/json'},
@ -49,17 +56,18 @@ class ControlClient(object):
break break
except Exception, exc: except Exception, exc:
WormConfiguration.current_server = '' WormConfiguration.current_server = ""
LOG.warn("Error connecting to control server %s: %s", server, exc) LOG.warn("Error connecting to control server %s: %s", server, exc)
if not WormConfiguration.current_server: if not WormConfiguration.current_server:
if not ControlClient.proxies: if not ControlClient.proxies:
LOG.info("Starting tunnel lookup...") LOG.info("Starting tunnel lookup...")
proxy_find = tunnel.find_tunnel(default=default_tunnel) proxy_find = tunnel.find_tunnel(default=default_tunnel)
if proxy_find: if proxy_find:
LOG.info("Found tunnel at %s:%s" % proxy_find) proxy_address, proxy_port = proxy_find
ControlClient.proxies['https'] = 'https://%s:%s' % proxy_find LOG.info("Found tunnel at %s:%s" % (proxy_address, proxy_port))
ControlClient.wakeup(parent) ControlClient.proxies['https'] = 'https://%s:%s' % (proxy_address, proxy_port)
ControlClient.wakeup(parent=parent)
else: else:
LOG.info("No tunnel found") LOG.info("No tunnel found")
@ -170,6 +178,7 @@ class ControlClient(object):
return None return None
else: else:
proxy_class = HTTPConnectProxy proxy_class = HTTPConnectProxy
target_addr, target_port = None, None target_addr, target_port = WormConfiguration.current_server.split(':', 1)
target_port = int(target_port)
return tunnel.MonkeyTunnel(proxy_class, target_addr=target_addr, target_port=target_port) return tunnel.MonkeyTunnel(proxy_class, target_addr=target_addr, target_port=target_port)

View File

@ -112,10 +112,13 @@ class HTTPConnectProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
# just provide a tunnel, transfer the data with no modification # just provide a tunnel, transfer the data with no modification
req = self req = self
reqbody = None reqbody = None
import pdb
pdb.set_trace()
req.path = "https://%s/" % req.path.replace(':443', '') req.path = "https://%s/" % req.path.replace(':443', '')
u = urlsplit(req.path) u = urlsplit(req.path)
address = (u.hostname, u.port or 443) address = (u.hostname, u.port or 443)
uri = u
try: try:
conn = socket.create_connection(address) conn = socket.create_connection(address)
except socket.error: except socket.error:
@ -141,9 +144,8 @@ class HTTPConnectProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
conn.close() conn.close()
def log_message(self, format, *args): def log_message(self, format, *args):
LOG.debug("HTTPConnectProxyHandler: %s - - [%s] %s" % (self.address_string(), LOG.debug("HTTPConnectProxyHandler: %s - [%s] %s" %
self.log_date_time_string(), (self.address_string(), self.log_date_time_string(), format % args))
format % args))
class InternalHTTPServer(BaseHTTPServer.HTTPServer): class InternalHTTPServer(BaseHTTPServer.HTTPServer):
@ -171,6 +173,7 @@ class HTTPServer(threading.Thread):
def run(self): def run(self):
class TempHandler(FileServHTTPRequestHandler): class TempHandler(FileServHTTPRequestHandler):
filename = self._filename filename = self._filename
@staticmethod @staticmethod
def report_download(): def report_download():
self.downloads += 1 self.downloads += 1
@ -192,6 +195,5 @@ class HTTPConnectProxy(TransportProxyBase):
def run(self): def run(self):
httpd = InternalHTTPServer((self.local_host, self.local_port), HTTPConnectProxyHandler) httpd = InternalHTTPServer((self.local_host, self.local_port), HTTPConnectProxyHandler)
httpd.timeout = 10 httpd.timeout = 10
while not self._stopped: while not self._stopped:
httpd.handle_request() httpd.handle_request()

View File

@ -46,7 +46,7 @@ def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT):
while True: while True:
try: try:
answer, address = sock.recvfrom(BUFFER_READ) answer, address = sock.recvfrom(BUFFER_READ)
if not answer in ['?', '+', '-']: if answer not in ['?', '+', '-']:
tunnels.append(answer) tunnels.append(answer)
except socket.timeout: except socket.timeout:
break break
@ -58,7 +58,7 @@ def find_tunnel(default=None, attempts=3, timeout=DEFAULT_TIMEOUT):
continue continue
LOG.debug("Checking tunnel %s:%s", address, port) LOG.debug("Checking tunnel %s:%s", address, port)
is_open,_ = check_port_tcp(address, int(port)) is_open, _ = check_port_tcp(address, int(port))
if not is_open: if not is_open:
LOG.debug("Could not connect to %s:%s", address, port) LOG.debug("Could not connect to %s:%s", address, port)
continue continue
@ -111,7 +111,11 @@ class MonkeyTunnel(Thread):
return return
proxy = self._proxy_class(local_port=self.local_port, dest_host=self._target_addr, dest_port=self._target_port) proxy = self._proxy_class(local_port=self.local_port, dest_host=self._target_addr, dest_port=self._target_port)
LOG.info("Running tunnel using proxy class: %s, on port %s", proxy.__class__.__name__, self.local_port) LOG.info("Running tunnel using proxy class: %s, listening on port %s, routing to: %s:%s",
proxy.__class__.__name__,
self.local_port,
self._target_addr,
self._target_port)
proxy.start() proxy.start()
while not self._stopped: while not self._stopped:

View File

@ -1,7 +1,6 @@
import os import os
from flask import Flask, request, abort, send_from_directory from flask import Flask, request, abort, send_from_directory
from flask.ext import restful from flask.ext import restful
from flask.ext.restful import reqparse
from flask.ext.pymongo import PyMongo from flask.ext.pymongo import PyMongo
from flask import make_response from flask import make_response
import bson.json_util import bson.json_util
@ -10,39 +9,39 @@ from datetime import datetime
import dateutil.parser import dateutil.parser
MONKEY_DOWNLOADS = [ MONKEY_DOWNLOADS = [
{ {
'type' : 'linux', 'type': 'linux',
'machine' : 'x86_64', 'machine': 'x86_64',
'filename' : 'monkey-linux-64', 'filename': 'monkey-linux-64',
}, },
{ {
'type' : 'linux', 'type': 'linux',
'machine' : 'i686', 'machine': 'i686',
'filename' : 'monkey-linux-32', 'filename': 'monkey-linux-32',
}, },
{ {
'type' : 'linux', 'type': 'linux',
'filename' : 'monkey-linux-32', 'filename': 'monkey-linux-32',
}, },
{ {
'type' : 'windows', 'type': 'windows',
'machine' : 'x86', 'machine': 'x86',
'filename' : 'monkey-linux-32.exe', 'filename': 'monkey-linux-32.exe',
}, },
{ {
'type' : 'windows', 'type': 'windows',
'machine' : 'amd64', 'machine': 'amd64',
'filename' : 'monkey-windows-64.exe', 'filename': 'monkey-windows-64.exe',
}, },
{ {
'type' : 'windows', 'type': 'windows',
'filename' : 'monkey-windows-32.exe', 'filename': 'monkey-windows-32.exe',
}, },
] ]
MONGO_URL = os.environ.get('MONGO_URL') MONGO_URL = os.environ.get('MONGO_URL')
if not MONGO_URL: if not MONGO_URL:
MONGO_URL = "mongodb://localhost:27017/monkeyisland"; MONGO_URL = "mongodb://localhost:27017/monkeyisland"
app = Flask(__name__) app = Flask(__name__)
app.config['MONGO_URI'] = MONGO_URL app.config['MONGO_URI'] = MONGO_URL
@ -54,7 +53,7 @@ class Monkey(restful.Resource):
guid = kw.get('guid') guid = kw.get('guid')
timestamp = request.args.get('timestamp') timestamp = request.args.get('timestamp')
if None != guid: if guid:
return mongo.db.monkey.find_one_or_404({"guid": guid}) return mongo.db.monkey.find_one_or_404({"guid": guid})
else: else:
result = {'timestamp': datetime.now().isoformat()} result = {'timestamp': datetime.now().isoformat()}
@ -65,8 +64,8 @@ class Monkey(restful.Resource):
return result return result
def patch(self, guid): def patch(self, guid):
monkey_json = json.loads(request.data); monkey_json = json.loads(request.data)
update = {"$set" : {'modifytime':datetime.now()}} update = {"$set": {'modifytime': datetime.now()}}
if monkey_json.has_key('keepalive'): if monkey_json.has_key('keepalive'):
update['$set']['keepalive'] = dateutil.parser.parse(monkey_json['keepalive']) update['$set']['keepalive'] = dateutil.parser.parse(monkey_json['keepalive'])
@ -91,7 +90,7 @@ class Monkey(restful.Resource):
# if new monkey, change config according to "new monkeys" config. # if new monkey, change config according to "new monkeys" config.
db_monkey = mongo.db.monkey.find_one({"guid": monkey_json["guid"]}) db_monkey = mongo.db.monkey.find_one({"guid": monkey_json["guid"]})
if not db_monkey: if not db_monkey:
new_config = mongo.db.config.find_one({'name' : 'newconfig'}) or {} new_config = mongo.db.config.find_one({'name': 'newconfig'}) or {}
monkey_json['config'] = monkey_json.get('config', {}) monkey_json['config'] = monkey_json.get('config', {})
monkey_json['config'].update(new_config) monkey_json['config'].update(new_config)
else: else:
@ -106,13 +105,14 @@ class Monkey(restful.Resource):
# try to find new monkey parent # try to find new monkey parent
parent = monkey_json.get('parent') parent = monkey_json.get('parent')
if (not parent or parent == monkey_json.get('guid')) and monkey_json.has_key('ip_addresses'): if (not parent or parent == monkey_json.get('guid')) and monkey_json.has_key('ip_addresses'):
exploit_telem = [x for x in mongo.db.telemetry.find({'telem_type': {'$eq' : 'exploit'}, \ exploit_telem = [x for x in
'data.machine.ip_addr' : {'$in' : monkey_json['ip_addresses']}})] mongo.db.telemetry.find({'telem_type': {'$eq': 'exploit'}, 'data.machine.ip_addr':
{'$in': monkey_json['ip_addresses']}})]
if 1 == len(exploit_telem): if 1 == len(exploit_telem):
monkey_json['parent'] = exploit_telem[0].get('monkey_guid') monkey_json['parent'] = exploit_telem[0].get('monkey_guid')
return mongo.db.monkey.update({"guid": monkey_json["guid"]}, return mongo.db.monkey.update({"guid": monkey_json["guid"]},
{"$set" : monkey_json}, {"$set": monkey_json},
upsert=True) upsert=True)
@ -124,9 +124,9 @@ class Telemetry(restful.Resource):
result = {'timestamp': datetime.now().isoformat()} result = {'timestamp': datetime.now().isoformat()}
find_filter = {} find_filter = {}
if None != monkey_guid: if monkey_guid:
find_filter["monkey_guid"] = {'$eq': monkey_guid} find_filter["monkey_guid"] = {'$eq': monkey_guid}
if None != timestamp: if timestamp:
find_filter['timestamp'] = {'$gt': dateutil.parser.parse(timestamp)} find_filter['timestamp'] = {'$gt': dateutil.parser.parse(timestamp)}
result['objects'] = [x for x in mongo.db.telemetry.find(find_filter)] result['objects'] = [x for x in mongo.db.telemetry.find(find_filter)]
@ -142,15 +142,15 @@ class Telemetry(restful.Resource):
try: try:
if telemetry_json.get('telem_type') == 'exploit': if telemetry_json.get('telem_type') == 'exploit':
update_parent = [] update_parent = []
for monkey in mongo.db.monkey.find({ "ip_addresses" : for monkey in mongo.db.monkey.find({"ip_addresses":
{'$elemMatch' : {'$elemMatch':
{ '$eq' : telemetry_json['data']['machine']['ip_addr'] }}}): {'$eq': telemetry_json['data']['machine']['ip_addr']}}}):
parent = monkey.get('parent') parent = monkey.get('parent')
if parent == monkey.get('guid') or None == parent: if parent == monkey.get('guid') or not parent:
update_parent.append(monkey) update_parent.append(monkey)
if 1 == len(update_parent): if 1 == len(update_parent):
update_parent[0]['parent'] = telemetry_json['monkey_guid'] update_parent[0]['parent'] = telemetry_json['monkey_guid']
mongo.db.monkey.update({"guid": update_parent[0]['guid']}, {"$set" : update_parent[0]}, upsert=False) mongo.db.monkey.update({"guid": update_parent[0]['guid']}, {"$set": update_parent[0]}, upsert=False)
except: except:
pass pass
@ -159,14 +159,14 @@ class Telemetry(restful.Resource):
class NewConfig(restful.Resource): class NewConfig(restful.Resource):
def get(self): def get(self):
config = mongo.db.config.find_one({'name' : 'newconfig'}) or {} config = mongo.db.config.find_one({'name': 'newconfig'}) or {}
if config.has_key('name'): if config.has_key('name'):
del config['name'] del config['name']
return config return config
def post(self): def post(self):
config_json = json.loads(request.data) config_json = json.loads(request.data)
return mongo.db.config.update({'name' : 'newconfig'}, {"$set" : config_json}, upsert=True) return mongo.db.config.update({'name': 'newconfig'}, {"$set": config_json}, upsert=True)
class MonkeyDownload(restful.Resource): class MonkeyDownload(restful.Resource):
@ -177,7 +177,7 @@ class MonkeyDownload(restful.Resource):
host_json = json.loads(request.data) host_json = json.loads(request.data)
host_os = host_json.get('os') host_os = host_json.get('os')
if os: if os:
result = None result = None
for download in MONKEY_DOWNLOADS: for download in MONKEY_DOWNLOADS:
if host_os.get('type') == download.get('type') and \ if host_os.get('type') == download.get('type') and \
host_os.get('machine') == download.get('machine'): host_os.get('machine') == download.get('machine'):
@ -242,4 +242,4 @@ api.add_resource(NewConfig, '/api/config/new')
api.add_resource(MonkeyDownload, '/api/monkey/download', '/api/monkey/download/', '/api/monkey/download/<string:path>') api.add_resource(MonkeyDownload, '/api/monkey/download', '/api/monkey/download/', '/api/monkey/download/<string:path>')
if __name__ == '__main__': if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, ssl_context=('server.crt', 'server.key')) app.run(host='0.0.0.0', debug=True, ssl_context=('server.crt', 'server.key'))