From d349f2628cfc82d73f8239c398cc15048bf5b55c Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Mon, 27 Jan 2020 17:44:18 +0200 Subject: [PATCH] Code changes that loosely implement the prototype of bootloader, but there still is a timeout --- monkey/infection_monkey/monkey.py | 4 ++ monkey/infection_monkey/transport/http.py | 15 +++++++ monkey/infection_monkey/tunnel.py | 5 ++- monkey/monkey_island/cc/bootloader_server.py | 41 +++++++++++++++++++ monkey/monkey_island/cc/main.py | 16 ++++++++ .../monkey_island/cc/resources/bootloader.py | 34 +++++---------- 6 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 monkey/monkey_island/cc/bootloader_server.py diff --git a/monkey/infection_monkey/monkey.py b/monkey/infection_monkey/monkey.py index 80d2d8642..2e6470cc0 100644 --- a/monkey/infection_monkey/monkey.py +++ b/monkey/infection_monkey/monkey.py @@ -216,6 +216,10 @@ class InfectionMonkey(object): # if host was exploited, before continue to closing the tunnel ensure the exploited host had its chance to # connect to the tunnel + + #TODO change back + time.sleep(WormConfiguration.keep_tunnel_open_time) + if len(self._exploited_machines) > 0: time_to_sleep = WormConfiguration.keep_tunnel_open_time LOG.info("Sleeping %d seconds for exploited machines to connect to tunnel", time_to_sleep) diff --git a/monkey/infection_monkey/transport/http.py b/monkey/infection_monkey/transport/http.py index ae7a6934c..a3cf6b2b6 100644 --- a/monkey/infection_monkey/transport/http.py +++ b/monkey/infection_monkey/transport/http.py @@ -7,6 +7,8 @@ import urllib from logging import getLogger from urllib.parse import urlsplit +import requests + import infection_monkey.monkeyfs as monkeyfs from infection_monkey.transport.base import TransportProxyBase, update_last_serve_time from infection_monkey.network.tools import get_interface_to_target @@ -110,6 +112,19 @@ class HTTPConnectProxyHandler(http.server.BaseHTTPRequestHandler): proxy_via = None # pseudonym of the proxy in Via header, set to None not to modify original Via header protocol_version = "HTTP/1.1" + def do_POST(self): + content_length = int(self.headers['Content-Length']) # <--- Gets the size of data + post_data = self.rfile.read(content_length).decode() # <--- Gets the data itself + r = requests.post(url=self.path, data=post_data) + if (r.status_code != 200): + # somehow forward post request to the next proxy + r = requests.post(url=self.path, data=post_data, proxy=self.path) + if (r.status_code != 200): + return self.send_response(404) + self.send_response(200) + self.end_headers() + self.wfile.write(r.content) + def version_string(self): return "" diff --git a/monkey/infection_monkey/tunnel.py b/monkey/infection_monkey/tunnel.py index 3544f46f3..3a7d23256 100644 --- a/monkey/infection_monkey/tunnel.py +++ b/monkey/infection_monkey/tunnel.py @@ -126,7 +126,10 @@ class MonkeyTunnel(Thread): def run(self): self._broad_sock = _set_multicast_socket(self._timeout) self.l_ips = local_ips() - self.local_port = get_free_tcp_port() + + #TODO change back + self.local_port = 5002 + #self.local_port = get_free_tcp_port() if not self.local_port: return diff --git a/monkey/monkey_island/cc/bootloader_server.py b/monkey/monkey_island/cc/bootloader_server.py new file mode 100644 index 000000000..1638c6316 --- /dev/null +++ b/monkey/monkey_island/cc/bootloader_server.py @@ -0,0 +1,41 @@ +from http.server import HTTPServer, BaseHTTPRequestHandler +from urllib import parse +import urllib3 + +import requests +import pymongo + +# Disable "unverified certificate" warnings when sending requests to island +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +class BootloaderHttpServer(HTTPServer): + + def __init__(self, mongo_url): + self.mongo_client = pymongo.MongoClient(mongo_url) + server_address = ('', 5001) + super().__init__(server_address, BootloaderHTTPRequestHandler) + + +class BootloaderHTTPRequestHandler(BaseHTTPRequestHandler): + + def do_POST(self): + content_length = int(self.headers['Content-Length']) + post_data = self.rfile.read(content_length).decode() + conf = self.server.mongo_client['monkeyisland']['config'].find_one({'name': 'newconfig'}) + if not conf: + conf = self.server.mongo_client['monkeyisland']['config'].find_one({'name': 'initial'}) + island_server_path = BootloaderHTTPRequestHandler.get_bootloader_resource_path_from_config(conf) + r = requests.post(url=island_server_path, data=post_data, verify=False) + if r.status_code != 200: + self.send_response(404) + else: + self.send_response(200) + self.end_headers() + self.wfile.write(r.content) + self.connection.close() + + @staticmethod + def get_bootloader_resource_path_from_config(config): + address = config['cnc']['servers']['current_server'] + return parse.urljoin("https://"+address, "api/bootloader") diff --git a/monkey/monkey_island/cc/main.py b/monkey/monkey_island/cc/main.py index 17c537aeb..31e227ff1 100644 --- a/monkey/monkey_island/cc/main.py +++ b/monkey/monkey_island/cc/main.py @@ -3,6 +3,7 @@ import os.path import sys import time import logging +from threading import Thread MINIMUM_MONGO_DB_VERSION_REQUIRED = "3.6.0" @@ -25,9 +26,24 @@ from monkey_island.cc.utils import local_ip_addresses from monkey_island.cc.environment.environment import env from monkey_island.cc.database import is_db_server_up, get_db_version from monkey_island.cc.resources.monkey_download import MonkeyDownload +from monkey_island.cc.bootloader_server import BootloaderHttpServer def main(): + + logger.info("Starting bootloader server") + mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url()) + bootloader_server_thread = Thread(target=BootloaderHttpServer(mongo_url).serve_forever, daemon=True) + # island_server_thread = Thread(target=start_island_server) + + bootloader_server_thread.start() + #island_server_thread.start() + start_island_server() + bootloader_server_thread.join() + #island_server_thread.join() + + +def start_island_server(): from tornado.wsgi import WSGIContainer from tornado.httpserver import HTTPServer from tornado.ioloop import IOLoop diff --git a/monkey/monkey_island/cc/resources/bootloader.py b/monkey/monkey_island/cc/resources/bootloader.py index 78b6f8015..672f7033f 100644 --- a/monkey/monkey_island/cc/resources/bootloader.py +++ b/monkey/monkey_island/cc/resources/bootloader.py @@ -1,24 +1,17 @@ -import json -from datetime import datetime -import dateutil.parser import flask_restful -from flask import request +from flask import request, make_response -from monkey_island.cc.consts import DEFAULT_MONKEY_TTL_EXPIRY_DURATION_IN_SECONDS -from monkey_island.cc.database import mongo -from monkey_island.cc.models.monkey_ttl import create_monkey_ttl_document -from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.node import NodeService WINDOWS_VERSIONS = { - "5.0" : "Windows 2000", - "5.1" : "Windows XP", - "5.2" : "Windows XP/server 2003", - "6.0" : "Windows Vista/server 2008", - "6.1" : "Windows 7/server 2008R2", - "6.2" : "Windows 8/server 2012", - "6.3" : "Windows 8.1/server 2012R2", - "10.0" : "Windows 10/server 2016-2019" + "5.0": "Windows 2000", + "5.1": "Windows XP", + "5.2": "Windows XP/server 2003", + "6.0": "Windows Vista/server 2008", + "6.1": "Windows 7/server 2008R2", + "6.2": "Windows 8/server 2012", + "6.3": "Windows 8.1/server 2012R2", + "10.0": "Windows 10/server 2016-2019" } @@ -27,13 +20,8 @@ class Bootloader(flask_restful.Resource): # Used by monkey. can't secure. def post(self, **kw): os_version = request.data.decode().split(" ") - if (os_version[0] == "W"): + if (os_version[0][0] == "W"): os_type = "windows" os_version = os_version[1:] - - return {"id": "Abc"} - - def get(self, guid=None, **kw): - NodeService.update_dead_monkeys() - return {} + return make_response({"status": "OK"}, 200)