improved local interface selection when exploiting

This commit is contained in:
itsikkes 2016-09-08 12:30:40 +03:00
parent d2203b2220
commit b3322b2541
4 changed files with 98 additions and 10 deletions

View File

@ -292,7 +292,7 @@ class RdpExploiter(HostExploiter):
LOG.info("Trying RDP logging into victim %r with user %s and password '%s'", LOG.info("Trying RDP logging into victim %r with user %s and password '%s'",
host, self._config.psexec_user, password) 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) client_factory = CMDClientFactory(self._config.psexec_user, password, "", command)

View File

@ -1,4 +1,7 @@
import os import os
import sys
import socket
import struct
import ntpath import ntpath
import pprint import pprint
import logging import logging
@ -8,7 +11,7 @@ import monkeyfs
from difflib import get_close_matches from difflib import get_close_matches
from network import local_ips from network import local_ips
from transport import HTTPServer 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 network.firewall import app as firewall
from impacket.dcerpc.v5 import transport, srvs from impacket.dcerpc.v5 import transport, srvs
from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError from impacket.dcerpc.v5.dcom.wmi import DCERPCSessionError
@ -369,7 +372,7 @@ class HTTPTools(object):
local_port = get_free_tcp_port() local_port = get_free_tcp_port()
if not local_ip: 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(): if not firewall.listen_allowed():
return None, None 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 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): def get_target_monkey(host):
from control import ControlClient from control import ControlClient
import platform import platform

View File

@ -30,9 +30,11 @@ if sys.platform == "win32":
network_adapters.append((add["addr"], add["netmask"])) network_adapters.append((add["addr"], add["netmask"]))
return network_adapters return network_adapters
else: def get_routes():
import fcntl raise NotImplementedError()
else:
from fcntl import ioctl
def get_host_subnets(only_ips=False): def get_host_subnets(only_ips=False):
"""Get the list of Linux network adapters.""" """Get the list of Linux network adapters."""
@ -46,7 +48,7 @@ else:
offset2 = 32 offset2 = 32
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
names = array.array('B', '\0' * max_bytes) names = array.array('B', '\0' * max_bytes)
outbytes = struct.unpack('iL', fcntl.ioctl( outbytes = struct.unpack('iL', ioctl(
sock.fileno(), sock.fileno(),
0x8912, 0x8912,
struct.pack('iL', max_bytes, names.buffer_info()[0])))[0] struct.pack('iL', max_bytes, names.buffer_info()[0])))[0]
@ -54,13 +56,13 @@ else:
for n_cnt in xrange(0, outbytes, offset2)] for n_cnt in xrange(0, outbytes, offset2)]
network_adapters = [] network_adapters = []
for adapter_name in adapter_names: for adapter_name in adapter_names:
ip_address = socket.inet_ntoa(fcntl.ioctl( ip_address = socket.inet_ntoa(ioctl(
sock.fileno(), sock.fileno(),
0x8915, 0x8915,
struct.pack('256s', adapter_name))[20:24]) struct.pack('256s', adapter_name))[20:24])
if ip_address.startswith('127'): if ip_address.startswith('127'):
continue continue
subnet_mask = socket.inet_ntoa(fcntl.ioctl( subnet_mask = socket.inet_ntoa(ioctl(
sock.fileno(), sock.fileno(),
0x891b, 0x891b,
struct.pack('256s', adapter_name))[20:24]) struct.pack('256s', adapter_name))[20:24])
@ -72,10 +74,56 @@ else:
return network_adapters return network_adapters
def local_ips(): def local_ips():
return get_host_subnets(only_ips=True) 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): def get_free_tcp_port(min_range=1000, max_range=65535):
start_range = min(1, min_range) start_range = min(1, min_range)

View File

@ -32,7 +32,11 @@ Windows:
type > C:\Python27\Lib\site-packages\zope\__init__.py type > C:\Python27\Lib\site-packages\zope\__init__.py
7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe: 7. Download and extract UPX binary to [source-path]\monkey\chaos_monkey\bin\upx.exe:
http://upx.sourceforge.net/download/upx391w.zip 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): Linux (Tested on Ubuntu 12.04):
1. Run: 1. Run: