From b3322b25410f90c600164209e35ca494689f84d2 Mon Sep 17 00:00:00 2001 From: itsikkes Date: Thu, 8 Sep 2016 12:30:40 +0300 Subject: [PATCH 1/2] improved local interface selection when exploiting --- chaos_monkey/exploit/rdpgrinder.py | 2 +- chaos_monkey/exploit/tools.py | 40 +++++++++++++++++++- chaos_monkey/network/info.py | 60 +++++++++++++++++++++++++++--- chaos_monkey/readme.txt | 6 ++- 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/chaos_monkey/exploit/rdpgrinder.py b/chaos_monkey/exploit/rdpgrinder.py index c0cc6aa27..6d2bbde18 100644 --- a/chaos_monkey/exploit/rdpgrinder.py +++ b/chaos_monkey/exploit/rdpgrinder.py @@ -292,7 +292,7 @@ class RdpExploiter(HostExploiter): LOG.info("Trying RDP logging into victim %r with user %s and password '%s'", host, self._config.psexec_user, password) - LOG.info("RDP logged in to %r", host) + LOG.info("RDP connected to %r", host) client_factory = CMDClientFactory(self._config.psexec_user, password, "", command) diff --git a/chaos_monkey/exploit/tools.py b/chaos_monkey/exploit/tools.py index 9fab2d715..b6cee68ac 100644 --- a/chaos_monkey/exploit/tools.py +++ b/chaos_monkey/exploit/tools.py @@ -1,4 +1,7 @@ import os +import sys +import socket +import struct import ntpath import pprint import logging @@ -8,7 +11,7 @@ import monkeyfs from difflib import get_close_matches from network import local_ips from transport import HTTPServer -from network.info import get_free_tcp_port +from network.info import get_free_tcp_port, get_routes from network.firewall import app as firewall from impacket.dcerpc.v5 import transport, srvs from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError @@ -369,7 +372,7 @@ class HTTPTools(object): local_port = get_free_tcp_port() if not local_ip: - local_ip = get_close_matches(host.ip_addr, local_ips())[0] + local_ip = get_interface_to_target(host.ip_addr) if not firewall.listen_allowed(): return None, None @@ -381,6 +384,39 @@ class HTTPTools(object): return "http://%s:%s/%s" % (local_ip, local_port, urllib.quote(os.path.basename(src_path))), httpd +def get_interface_to_target(dst): + if sys.platform == "win32": + try: + import dnet + intf = dnet.intf() + inte = intf.get_dst(dnet.addr(dst)) + return str(inte['addr']).split("/")[0] + except ImportError: + # dnet lib is not installed + return get_close_matches(dst, local_ips())[0] + else: + # based on scapy implementation + + def atol(x): + ip = socket.inet_aton(x) + return struct.unpack("!I", ip)[0] + + routes = get_routes() + dst = atol(dst) + pathes = [] + for d, m, gw, i, a in routes: + aa = atol(a) + if aa == dst: + pathes.append((0xffffffffL, ("lo", a, "0.0.0.0"))) + if (dst & m) == (d & m): + pathes.append((m, (i, a, gw))) + if not pathes: + return None + pathes.sort() + ret = pathes[-1][1] + return ret[1] + + def get_target_monkey(host): from control import ControlClient import platform diff --git a/chaos_monkey/network/info.py b/chaos_monkey/network/info.py index d5e507846..59b40a089 100644 --- a/chaos_monkey/network/info.py +++ b/chaos_monkey/network/info.py @@ -30,9 +30,11 @@ if sys.platform == "win32": network_adapters.append((add["addr"], add["netmask"])) return network_adapters -else: - import fcntl + def get_routes(): + raise NotImplementedError() +else: + from fcntl import ioctl def get_host_subnets(only_ips=False): """Get the list of Linux network adapters.""" @@ -46,7 +48,7 @@ else: offset2 = 32 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) names = array.array('B', '\0' * max_bytes) - outbytes = struct.unpack('iL', fcntl.ioctl( + outbytes = struct.unpack('iL', ioctl( sock.fileno(), 0x8912, struct.pack('iL', max_bytes, names.buffer_info()[0])))[0] @@ -54,13 +56,13 @@ else: for n_cnt in xrange(0, outbytes, offset2)] network_adapters = [] for adapter_name in adapter_names: - ip_address = socket.inet_ntoa(fcntl.ioctl( + 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(fcntl.ioctl( + subnet_mask = socket.inet_ntoa(ioctl( sock.fileno(), 0x891b, struct.pack('256s', adapter_name))[20:24]) @@ -72,10 +74,56 @@ else: return network_adapters - def local_ips(): return get_host_subnets(only_ips=True) + def get_routes(): # based on scapy implementation for route parsing + LOOPBACK_NAME = "lo" + SIOCGIFADDR = 0x8915 # get PA address + SIOCGIFNETMASK = 0x891b # get network PA mask + RTF_UP = 0x0001 # Route usable + RTF_REJECT = 0x0200 + + try: + f = open("/proc/net/route", "r") + except IOError: + return [] + routes = [] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + ifreq = ioctl(s, SIOCGIFADDR, struct.pack("16s16x", LOOPBACK_NAME)) + addrfamily = struct.unpack("h", ifreq[16:18])[0] + if addrfamily == socket.AF_INET: + ifreq2 = ioctl(s, SIOCGIFNETMASK, struct.pack("16s16x", LOOPBACK_NAME)) + msk = socket.ntohl(struct.unpack("I", ifreq2[20:24])[0]) + dst = socket.ntohl(struct.unpack("I", ifreq[20:24])[0]) & msk + ifaddr = socket.inet_ntoa(ifreq[20:24]) + routes.append((dst, msk, "0.0.0.0", LOOPBACK_NAME, ifaddr)) + + for l in f.readlines()[1:]: + iff, dst, gw, flags, x, x, x, msk, x, x, x = l.split() + flags = int(flags, 16) + if flags & RTF_UP == 0: + continue + if flags & RTF_REJECT: + continue + try: + ifreq = ioctl(s, SIOCGIFADDR, struct.pack("16s16x", iff)) + except IOError: # interface is present in routing tables but does not have any assigned IP + ifaddr = "0.0.0.0" + else: + addrfamily = struct.unpack("h", ifreq[16:18])[0] + if addrfamily == socket.AF_INET: + ifaddr = socket.inet_ntoa(ifreq[20:24]) + else: + continue + routes.append((socket.htonl(long(dst, 16)) & 0xffffffffL, + socket.htonl(long(msk, 16)) & 0xffffffffL, + socket.inet_ntoa(struct.pack("I", long(gw, 16))), + iff, ifaddr)) + + f.close() + return routes + def get_free_tcp_port(min_range=1000, max_range=65535): start_range = min(1, min_range) diff --git a/chaos_monkey/readme.txt b/chaos_monkey/readme.txt index 21becbdc2..d25742016 100644 --- a/chaos_monkey/readme.txt +++ b/chaos_monkey/readme.txt @@ -32,7 +32,11 @@ Windows: type > C:\Python27\Lib\site-packages\zope\__init__.py 7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe: http://upx.sourceforge.net/download/upx391w.zip -8. Run [source-path]\monkey\chaos_monkey\build_windows.bat to build, output is in dist\monkey.exe +8. (Optional) For some exploits to work better, install 'dnet' python library. You'll need to compile it for your OS + or use a precompiled setup that can be found at: + 32bit: https://github.com/Kondziowy/scapy_win64/raw/master/win32/dnet-1.12.win32-py2.7.exe + 64bit: https://github.com/Kondziowy/scapy_win64/raw/master/win64/dnet-1.12.win-amd64-py2.7.exe +9. Run [source-path]\monkey\chaos_monkey\build_windows.bat to build, output is in dist\monkey.exe Linux (Tested on Ubuntu 12.04): 1. Run: From d1f218daadebd53860f8b0cf85cd945735194959 Mon Sep 17 00:00:00 2001 From: Daniel Goldberg Date: Tue, 13 Sep 2016 14:07:48 +0300 Subject: [PATCH 2/2] Don't dup pip list --- chaos_monkey/readme.txt | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/chaos_monkey/readme.txt b/chaos_monkey/readme.txt index d25742016..726f434df 100644 --- a/chaos_monkey/readme.txt +++ b/chaos_monkey/readme.txt @@ -15,21 +15,7 @@ Windows: 4. Download & Run get-pip.py https://bootstrap.pypa.io/get-pip.py 5. Run: - setx path "%path%;C:\Python27\;C:\Python27\Scripts" - python -m pip install enum34 - python -m pip install impacket - python -m pip install PyCrypto - python -m pip install pyasn1 - python -m pip install cffi - python -m pip install twisted - python -m pip install rdpy - python -m pip install requests - python -m pip install odict - python -m pip install paramiko - python -m pip install psutil - python -m pip install netifaces - python -m pip install PyInstaller - type > C:\Python27\Lib\site-packages\zope\__init__.py + Install the python packages listed in requirements.txt. Using pip install -r requirements.txt 7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe: http://upx.sourceforge.net/download/upx391w.zip 8. (Optional) For some exploits to work better, install 'dnet' python library. You'll need to compile it for your OS @@ -42,20 +28,8 @@ Linux (Tested on Ubuntu 12.04): 1. Run: sudo apt-get update sudo apt-get install python-pip python-dev libffi-dev upx libssl-dev libc++1 - sudo pip install enum34 - sudo pip install impacket - sudo pip install PyCrypto --upgrade - sudo pip install pyasn1 - sudo pip install cffi - sudo pip install zope.interface --upgrade - sudo pip install twisted - sudo pip install rdpy - sudo pip install requests --upgrade - sudo pip install odict - sudo pip install paramiko - sudo pip install psutil - sudo pip install netifaces - sudo pip install PyInstaller + Install the python packages listed in requirements.txt. + Using pip install -r requirements.txt sudo apt-get install winbind 2. Put source code in /home/user/Code/monkey/chaos_monkey 3. To build, run in terminal: