forked from p34709852/monkey
Merge remote-tracking branch 'origin/develop' into feature/refactor-monkey-island
This commit is contained in:
commit
11fa27a2f7
|
@ -1,3 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
gcc -c -Wall -Werror -fpic sc_monkey_runner.c
|
gcc -c -Wall -Werror -fpic -m64 sc_monkey_runner.c
|
||||||
gcc -shared -o sc_monkey_runner.so sc_monkey_runner.o
|
gcc -shared -m64 -o sc_monkey_runner_64.so sc_monkey_runner.o
|
||||||
|
rm sc_monkey_runner.o
|
||||||
|
strip sc_monkey_runner_64.so
|
||||||
|
gcc -c -Wall -Werror -fpic -m32 sc_monkey_runner.c
|
||||||
|
gcc -shared -m32 -o sc_monkey_runner_32.so sc_monkey_runner.o
|
||||||
|
rm sc_monkey_runner.o
|
||||||
|
strip sc_monkey_runner_32.so
|
|
@ -1,81 +1,56 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import array
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import psutil
|
import psutil
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import itertools
|
||||||
|
import netifaces
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
if sys.platform == "win32":
|
|
||||||
import netifaces
|
|
||||||
|
|
||||||
|
def get_host_subnets():
|
||||||
|
"""
|
||||||
|
Returns a list of subnets visible to host (omitting loopback and auto conf networks)
|
||||||
|
Each subnet item contains the host IP in that network + the subnet.
|
||||||
|
:return: List of dict, keys are "addr" and "subnet"
|
||||||
|
"""
|
||||||
|
ipv4_nets = [netifaces.ifaddresses(interface)[netifaces.AF_INET]
|
||||||
|
for interface in netifaces.interfaces()
|
||||||
|
if netifaces.AF_INET in netifaces.ifaddresses(interface)
|
||||||
|
]
|
||||||
|
# flatten
|
||||||
|
ipv4_nets = itertools.chain.from_iterable(ipv4_nets)
|
||||||
|
# remove loopback
|
||||||
|
ipv4_nets = [network for network in ipv4_nets if network['addr'] != '127.0.0.1']
|
||||||
|
# remove auto conf
|
||||||
|
ipv4_nets = [network for network in ipv4_nets if not network['addr'].startswith('169.254')]
|
||||||
|
for network in ipv4_nets:
|
||||||
|
if 'broadcast' in network:
|
||||||
|
network.pop('broadcast')
|
||||||
|
return ipv4_nets
|
||||||
|
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
|
||||||
def local_ips():
|
def local_ips():
|
||||||
local_hostname = socket.gethostname()
|
local_hostname = socket.gethostname()
|
||||||
return socket.gethostbyname_ex(local_hostname)[2]
|
return socket.gethostbyname_ex(local_hostname)[2]
|
||||||
|
|
||||||
|
|
||||||
def get_host_subnets(only_ips=False):
|
|
||||||
network_adapters = []
|
|
||||||
valid_ips = local_ips()
|
|
||||||
if only_ips:
|
|
||||||
return valid_ips
|
|
||||||
interfaces = [netifaces.ifaddresses(x) for x in netifaces.interfaces()]
|
|
||||||
for inte in interfaces:
|
|
||||||
if netifaces.AF_INET in inte:
|
|
||||||
for add in inte[netifaces.AF_INET]:
|
|
||||||
if "netmask" in add and add["addr"] in valid_ips:
|
|
||||||
network_adapters.append((add["addr"], add["netmask"]))
|
|
||||||
return network_adapters
|
|
||||||
|
|
||||||
def get_routes():
|
def get_routes():
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
from fcntl import ioctl
|
from fcntl import ioctl
|
||||||
|
|
||||||
def get_host_subnets(only_ips=False):
|
|
||||||
"""Get the list of Linux network adapters."""
|
|
||||||
max_bytes = 8096
|
|
||||||
is_64bits = sys.maxsize > 2 ** 32
|
|
||||||
if is_64bits:
|
|
||||||
offset1 = 16
|
|
||||||
offset2 = 40
|
|
||||||
else:
|
|
||||||
offset1 = 32
|
|
||||||
offset2 = 32
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
names = array.array('B', '\0' * max_bytes)
|
|
||||||
outbytes = struct.unpack('iL', ioctl(
|
|
||||||
sock.fileno(),
|
|
||||||
0x8912,
|
|
||||||
struct.pack('iL', max_bytes, names.buffer_info()[0])))[0]
|
|
||||||
adapter_names = [names.tostring()[n_cnt:n_cnt + offset1].split('\0', 1)[0]
|
|
||||||
for n_cnt in xrange(0, outbytes, offset2)]
|
|
||||||
network_adapters = []
|
|
||||||
for adapter_name in adapter_names:
|
|
||||||
ip_address = socket.inet_ntoa(ioctl(
|
|
||||||
sock.fileno(),
|
|
||||||
0x8915,
|
|
||||||
struct.pack('256s', adapter_name))[20:24])
|
|
||||||
if ip_address.startswith('127'):
|
|
||||||
continue
|
|
||||||
subnet_mask = socket.inet_ntoa(ioctl(
|
|
||||||
sock.fileno(),
|
|
||||||
0x891b,
|
|
||||||
struct.pack('256s', adapter_name))[20:24])
|
|
||||||
|
|
||||||
if only_ips:
|
|
||||||
network_adapters.append(ip_address)
|
|
||||||
else:
|
|
||||||
network_adapters.append((ip_address, subnet_mask))
|
|
||||||
|
|
||||||
return network_adapters
|
|
||||||
|
|
||||||
def local_ips():
|
def local_ips():
|
||||||
return get_host_subnets(only_ips=True)
|
ipv4_nets = get_host_subnets()
|
||||||
|
valid_ips = [network['addr'] for network in ipv4_nets]
|
||||||
|
return valid_ips
|
||||||
|
|
||||||
|
|
||||||
def get_routes(): # based on scapy implementation for route parsing
|
def get_routes(): # based on scapy implementation for route parsing
|
||||||
LOOPBACK_NAME = "lo"
|
LOOPBACK_NAME = "lo"
|
||||||
|
@ -141,6 +116,11 @@ def get_free_tcp_port(min_range=1000, max_range=65535):
|
||||||
|
|
||||||
|
|
||||||
def check_internet_access(services):
|
def check_internet_access(services):
|
||||||
|
"""
|
||||||
|
Checks if any of the services are accessible, over ICMP
|
||||||
|
:param services: List of IPs/hostnames
|
||||||
|
:return: boolean depending on internet access
|
||||||
|
"""
|
||||||
ping_str = "-n 1" if sys.platform.startswith("win") else "-c 1"
|
ping_str = "-n 1" if sys.platform.startswith("win") else "-c 1"
|
||||||
for host in services:
|
for host in services:
|
||||||
if os.system("ping " + ping_str + " " + host) == 0:
|
if os.system("ping " + ping_str + " " + host) == 0:
|
||||||
|
@ -149,19 +129,24 @@ def check_internet_access(services):
|
||||||
|
|
||||||
|
|
||||||
def get_ips_from_interfaces():
|
def get_ips_from_interfaces():
|
||||||
|
"""
|
||||||
|
Returns a list of IPs accessible in the host in each network interface, in the subnet.
|
||||||
|
Limits to a single class C if the network is larger
|
||||||
|
:return: List of IPs, marked as strings.
|
||||||
|
"""
|
||||||
res = []
|
res = []
|
||||||
ifs = get_host_subnets()
|
ifs = get_host_subnets()
|
||||||
for interface in ifs:
|
for net_interface in ifs:
|
||||||
ipint = ipaddress.ip_interface(u"%s/%s" % interface)
|
host_addr = ipaddress.ip_address(net_interface['addr'])
|
||||||
|
ip_interface = ipaddress.ip_interface(u"%s/%s" % (net_interface['addr'], net_interface['netmask']))
|
||||||
# limit subnet scans to class C only
|
# limit subnet scans to class C only
|
||||||
if ipint.network.num_addresses > 255:
|
if ip_interface.network.num_addresses > 255:
|
||||||
ipint = ipaddress.ip_interface(u"%s/24" % interface[0])
|
ip_interface = ipaddress.ip_interface(u"%s/24" % net_interface['addr'])
|
||||||
for addr in ipint.network.hosts():
|
addrs = [str(addr) for addr in ip_interface.network.hosts() if addr != host_addr]
|
||||||
if str(addr) == interface[0]:
|
res.extend(addrs)
|
||||||
continue
|
|
||||||
res.append(str(addr))
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
def get_ip_for_connection(target_ip):
|
def get_ip_for_connection(target_ip):
|
||||||
return None
|
return None
|
||||||
|
@ -171,7 +156,7 @@ else:
|
||||||
query_str = 'ip route get %s' % target_ip
|
query_str = 'ip route get %s' % target_ip
|
||||||
resp = check_output(query_str.split())
|
resp = check_output(query_str.split())
|
||||||
substr = resp.split()
|
substr = resp.split()
|
||||||
src = substr[substr.index('src')+1]
|
src = substr[substr.index('src') + 1]
|
||||||
return src
|
return src
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
|
@ -2,6 +2,7 @@ import sys
|
||||||
import socket
|
import socket
|
||||||
import psutil
|
import psutil
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from network.info import get_host_subnets, local_ips
|
||||||
|
|
||||||
__author__ = 'uri'
|
__author__ = 'uri'
|
||||||
|
|
||||||
|
@ -45,9 +46,19 @@ class InfoCollector(object):
|
||||||
self.info = {}
|
self.info = {}
|
||||||
|
|
||||||
def get_hostname(self):
|
def get_hostname(self):
|
||||||
self.info['hostname'] = socket.gethostname()
|
"""
|
||||||
|
Adds the fully qualified computer hostname to the system information.
|
||||||
|
:return: Nothing
|
||||||
|
"""
|
||||||
|
self.info['hostname'] = socket.getfqdn()
|
||||||
|
|
||||||
def get_process_list(self):
|
def get_process_list(self):
|
||||||
|
"""
|
||||||
|
Adds process information from the host to the system information.
|
||||||
|
Currently lists process name, ID, parent ID, command line
|
||||||
|
and the full image path of each process.
|
||||||
|
:return: Nothing
|
||||||
|
"""
|
||||||
processes = {}
|
processes = {}
|
||||||
for process in psutil.process_iter():
|
for process in psutil.process_iter():
|
||||||
try:
|
try:
|
||||||
|
@ -69,3 +80,12 @@ class InfoCollector(object):
|
||||||
}
|
}
|
||||||
pass
|
pass
|
||||||
self.info['process_list'] = processes
|
self.info['process_list'] = processes
|
||||||
|
|
||||||
|
def get_network_info(self):
|
||||||
|
"""
|
||||||
|
Adds network information from the host to the system information.
|
||||||
|
Currently updates with a list of networks accessible from host,
|
||||||
|
containing host ip and the subnet range.
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
self.info['network_info'] = {'networks': get_host_subnets()}
|
||||||
|
|
|
@ -14,4 +14,5 @@ class LinuxInfoCollector(InfoCollector):
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
self.get_hostname()
|
self.get_hostname()
|
||||||
self.get_process_list()
|
self.get_process_list()
|
||||||
|
self.get_network_info()
|
||||||
return self.info
|
return self.info
|
||||||
|
|
|
@ -14,6 +14,7 @@ class WindowsInfoCollector(InfoCollector):
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
self.get_hostname()
|
self.get_hostname()
|
||||||
self.get_process_list()
|
self.get_process_list()
|
||||||
|
self.get_network_info()
|
||||||
mimikatz_collector = MimikatzCollector()
|
mimikatz_collector = MimikatzCollector()
|
||||||
self.info["credentials"] = mimikatz_collector.get_logon_info()
|
self.info["credentials"] = mimikatz_collector.get_logon_info()
|
||||||
return self.info
|
return self.info
|
||||||
|
|
|
@ -1,35 +1,34 @@
|
||||||
How to set C&C server:
|
How to set C&C server:
|
||||||
|
|
||||||
---------------- On Windows ----------------:
|
---------------- On Windows ----------------:
|
||||||
1. Install python 2.7
|
1. Create bin folder
|
||||||
https://www.python.org/download/releases/2.7
|
1.1. create folder "bin" under monkey_island
|
||||||
2. Download & Run get-pip.py
|
2. Place portable version of Python 2.7
|
||||||
https://bootstrap.pypa.io/get-pip.py
|
2.1. Download and install from: https://www.python.org/download/releases/2.7/
|
||||||
3. Run:
|
2.2. Download & Run get-pip.py from: https://bootstrap.pypa.io/get-pip.py
|
||||||
setx path "%path%;C:\Python27\;C:\Python27\Scripts"
|
2.3. Install required python libraries using "python -m pip install -r monkey_island\requirements.txt"
|
||||||
python -m pip install flask
|
2.4. Copy Contents from Installation path (Usually C:\Python27) to monkey_island\bin\Python27
|
||||||
python -m pip install Flask-Pymongo
|
2.5. Copy Python27.dll from System32 folder (Usually C:\Windows\System32) to monkey_island\bin\Python27
|
||||||
python -m pip install Flask-Restful
|
2.6. (Optional) You may uninstall Python27 if you like.
|
||||||
python -m pip install python-dateutil
|
3. Place portable version of mongodb
|
||||||
mkdir MonkeyIsland\bin
|
3.1. Download from: http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip
|
||||||
mkdir MonkeyIsland\db
|
3.2. Extract contents from bin folder to monkey_island\bin\mongodb.
|
||||||
mkdir MonkeyIsland\cc\binaries
|
4. Place portable version of OpenSSL
|
||||||
4. Put monkey binaries in MonkeyIsland\cc\binaries:
|
4.1. Download from: http://downloads.sourceforge.net/gnuwin32/openssl-0.9.8h-1-bin.zip
|
||||||
|
4.2. Extract content from bin folder to monkey_island\bin\openssl
|
||||||
|
5. Download and install Microsoft Visual C++ Redisutable for Visual Studio 2017
|
||||||
|
5.1. Download and install from: https://go.microsoft.com/fwlink/?LinkId=746572
|
||||||
|
6. Generate SSL Certificate
|
||||||
|
6.1. run create_certificate.bat when your current working directory is monkey_island
|
||||||
|
7. Put chaos monkey binaries in monkey_island\cc\binaries (create folder if it doesn't exist):
|
||||||
monkey-linux-64 - monkey binary for linux 64bit
|
monkey-linux-64 - monkey binary for linux 64bit
|
||||||
monkey-linux-32 - monkey binary for linux 32bit
|
monkey-linux-32 - monkey binary for linux 32bit
|
||||||
monkey-windows-32.exe - monkey binary for windows 32bit
|
monkey-windows-32.exe - monkey binary for windows 32bit
|
||||||
monkey-windows-64.exe - monkey binary for windows 64bit
|
monkey-windows-64.exe - monkey binary for windows 64bit
|
||||||
4. Download MongoDB & Extract to MonkeyIsland\bin\mongodb
|
|
||||||
http://downloads.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-latest.zip
|
|
||||||
5. Install OpenSSL
|
|
||||||
https://slproweb.com/download/Win64OpenSSL_Light-1_0_2d.exe
|
|
||||||
6. Generate SSL Certificate, run create_certificate.bat when your current working directory is MonkeyIsland
|
|
||||||
7. Copy monkey island server to MonkeyIsland\cc
|
|
||||||
|
|
||||||
How to run:
|
How to run:
|
||||||
1. start run_mongodb.bat
|
1. start monkey_island\windows\run_server.bat (when your current working directory is monkey_island)
|
||||||
2. start run_cc.bat
|
2. to clear db, run clear_db.bat
|
||||||
3. to clear db, run clear_db.bat
|
|
||||||
|
|
||||||
---------------- On Linux ----------------:
|
---------------- On Linux ----------------:
|
||||||
1. Create the following directories:
|
1. Create the following directories:
|
||||||
|
|
|
@ -2,4 +2,3 @@
|
||||||
@pause
|
@pause
|
||||||
@rmdir /s /q db
|
@rmdir /s /q db
|
||||||
@mkdir db
|
@mkdir db
|
||||||
@pause
|
|
|
@ -1,4 +1,3 @@
|
||||||
C:\OpenSSL-Win64\bin\openssl.exe genrsa -out cc\server.key 1024
|
bin\openssl\openssl.exe genrsa -out cc\server.key 1024
|
||||||
C:\OpenSSL-Win64\bin\openssl.exe req -new -config C:\OpenSSL-Win64\bin\openssl.cfg -key cc\server.key -out cc\server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com"
|
bin\openssl\openssl.exe req -new -config bin\openssl\openssl.cfg -key cc\server.key -out cc\server.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=Monkey Department/CN=monkey.com"
|
||||||
C:\OpenSSL-Win64\bin\openssl.exe x509 -req -days 366 -in cc\server.csr -signkey cc\server.key -out cc\server.crt
|
bin\openssl\openssl.exe x509 -req -days 366 -in cc\server.csr -signkey cc\server.key -out cc\server.crt
|
||||||
pause
|
|
|
@ -1,4 +1,4 @@
|
||||||
@title C^&C Server
|
@title C^&C Server
|
||||||
@cd cc
|
@pushd cc
|
||||||
@main.py
|
@..\bin\Python27\python main.py
|
||||||
@pause
|
@popd
|
|
@ -1,3 +1,2 @@
|
||||||
@title MongoDB
|
@title MongoDB
|
||||||
@bin\mongodb\mongod.exe --dbpath db
|
@bin\mongodb\mongod.exe --dbpath db
|
||||||
@pause
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
if not exist db mkdir db
|
||||||
|
start windows\run_mongodb.bat
|
||||||
|
start windows\run_cc.bat
|
Loading…
Reference in New Issue