diff --git a/bin/conpot b/bin/conpot index ccaf700b..5e293eb6 100755 --- a/bin/conpot +++ b/bin/conpot @@ -364,156 +364,136 @@ def main(): public_ip = None if config.getboolean("fetch_public_ip", "enabled"): public_ip = ext_ip.get_ext_ip(config) - if config.getboolean("change_mac_addr", "enabled"): - if os.getuid() == 0: - logger.info("Attempting to change mac address.") - mac_addr.change_mac(config=config) - else: - logger.info("Changing mac address require sudo permissions. Skipping") - # no need to fork process when we don't want to change MAC address - pid = 0 - if config.getboolean("change_mac_addr", "enabled"): - pid = gevent.fork() - if pid == 0: - for protocol_name, server_class in protocols.name_mapping.items(): - protocol_template = os.path.join( - root_template_directory, protocol_name, "{0}.xml".format(protocol_name) + + for protocol_name, server_class in protocols.name_mapping.items(): + protocol_template = os.path.join( + root_template_directory, protocol_name, "{0}.xml".format(protocol_name) + ) + if os.path.isfile(protocol_template): + xsd_file = os.path.join( + package_directory, + "protocols", + protocol_name, + "{0}.xsd".format(protocol_name), ) - if os.path.isfile(protocol_template): - xsd_file = os.path.join( - package_directory, - "protocols", - protocol_name, - "{0}.xsd".format(protocol_name), - ) - validate_template(protocol_template, xsd_file) - dom_protocol = etree.parse(protocol_template) - if dom_protocol.xpath("//{0}".format(protocol_name)): - if ast.literal_eval( - dom_protocol.xpath("//{0}/@enabled".format(protocol_name))[0] - ): - host = dom_protocol.xpath("//{0}/@host".format(protocol_name))[ - 0 - ] - # -- > Are we running on testing config? - if "testing.cfg" in args.config: - if "127." not in host: - if not args.force: - logger.error( - "To run conpot on a non local interface, please specify -f option" - ) - sys.exit(1) - port = ast.literal_eval( - dom_protocol.xpath("//{0}/@port".format(protocol_name))[0] - ) - server = server_class( - protocol_template, root_template_directory, args - ) - greenlet = spawn_startable_greenlet(server, host, port) - greenlet.link_exception(on_unhandled_greenlet_exception) - servers.append((server, greenlet)) - logger.info( - "Found and enabled {} protocol.".format( - protocol_name, server - ) - ) - else: + validate_template(protocol_template, xsd_file) + dom_protocol = etree.parse(protocol_template) + if dom_protocol.xpath("//{0}".format(protocol_name)): + if ast.literal_eval( + dom_protocol.xpath("//{0}/@enabled".format(protocol_name))[0] + ): + host = dom_protocol.xpath("//{0}/@host".format(protocol_name))[ + 0 + ] + # -- > Are we running on testing config? + if "testing.cfg" in args.config: + if "127." not in host: + if not args.force: + logger.error( + "To run conpot on a non local interface, please specify -f option" + ) + sys.exit(1) + port = ast.literal_eval( + dom_protocol.xpath("//{0}/@port".format(protocol_name))[0] + ) + server = server_class( + protocol_template, root_template_directory, args + ) + greenlet = spawn_startable_greenlet(server, host, port) + greenlet.link_exception(on_unhandled_greenlet_exception) + servers.append((server, greenlet)) logger.info( - "{} available but disabled by configuration.".format( - protocol_name + "Found and enabled {} protocol.".format( + protocol_name, server ) ) else: - logger.debug( - "No {} template found. Service will remain unconfigured/stopped.".format( + logger.info( + "{} available but disabled by configuration.".format( protocol_name ) ) - - log_worker = LogWorker(config, dom_base, session_manager, public_ip) - greenlet = spawn_startable_greenlet(log_worker) - greenlet.link_exception(on_unhandled_greenlet_exception) - servers.append((log_worker, greenlet)) - - # TODO: Line up Proxy init with other protocols - template_proxy = os.path.join(root_template_directory, "proxy", "proxy.xml") - if os.path.isfile(template_proxy): - xsd_file = os.path.join( - os.path.dirname(inspect.getfile(Proxy)), "proxy.xsd" - ) - validate_template(template_proxy, xsd_file) - dom_proxy = etree.parse(template_proxy) - if dom_proxy.xpath("//proxies"): - if ast.literal_eval(dom_proxy.xpath("//proxies/@enabled")[0]): - proxies = dom_proxy.xpath("//proxies/*") - for p in proxies: - name = p.attrib["name"] - host = p.attrib["host"] - keyfile = None - certfile = None - if "keyfile" in p.attrib and "certfile" in p.attrib: - keyfile = p.attrib["keyfile"] - certfile = p.attrib["certfile"] - - # if path is absolute we assert that the cert and key is located in - # the templates ssl standard location - - if not os.path.isabs(keyfile): - keyfile = os.path.join( - os.path.dirname(root_template_directory), - "ssl", - keyfile, - ) - certfile = os.path.join( - os.path.dirname(root_template_directory), - "ssl", - certfile, - ) - port = ast.literal_eval(p.attrib["port"]) - proxy_host = p.xpath("./proxy_host/text()")[0] - proxy_port = ast.literal_eval(p.xpath("./proxy_port/text()")[0]) - decoder = p.xpath("./decoder/text()") - if len(decoder) > 0: - decoder = decoder[0] - else: - decoder = None - proxy_instance = Proxy( - name, proxy_host, proxy_port, decoder, keyfile, certfile - ) - proxy_server = proxy_instance.get_server(host, port) - proxy_greenlet = spawn_startable_greenlet(proxy_server) - proxy_greenlet.link_exception(on_unhandled_greenlet_exception) - servers.append((proxy_instance, proxy_greenlet)) - else: - logger.info("Proxy available but disabled by template.") else: - logger.info( - "No proxy template found. Service will remain unconfigured/stopped." + logger.debug( + "No {} template found. Service will remain unconfigured/stopped.".format( + protocol_name + ) ) - try: - if len(servers) > 0: - gevent.wait() - except KeyboardInterrupt: - logging.info("Stopping Conpot") - for server, greenlet in servers: - logging.debug(f"Shutting down {greenlet.name}") - server.stop() - greenlet.get() - finally: - conpot_core.close_fs() + log_worker = LogWorker(config, dom_base, session_manager, public_ip) + greenlet = spawn_startable_greenlet(log_worker) + greenlet.link_exception(on_unhandled_greenlet_exception) + servers.append((log_worker, greenlet)) + # TODO: Line up Proxy init with other protocols + template_proxy = os.path.join(root_template_directory, "proxy", "proxy.xml") + if os.path.isfile(template_proxy): + xsd_file = os.path.join( + os.path.dirname(inspect.getfile(Proxy)), "proxy.xsd" + ) + validate_template(template_proxy, xsd_file) + dom_proxy = etree.parse(template_proxy) + if dom_proxy.xpath("//proxies"): + if ast.literal_eval(dom_proxy.xpath("//proxies/@enabled")[0]): + proxies = dom_proxy.xpath("//proxies/*") + for p in proxies: + name = p.attrib["name"] + host = p.attrib["host"] + keyfile = None + certfile = None + if "keyfile" in p.attrib and "certfile" in p.attrib: + keyfile = p.attrib["keyfile"] + certfile = p.attrib["certfile"] + + # if path is absolute we assert that the cert and key is located in + # the templates ssl standard location + + if not os.path.isabs(keyfile): + keyfile = os.path.join( + os.path.dirname(root_template_directory), + "ssl", + keyfile, + ) + certfile = os.path.join( + os.path.dirname(root_template_directory), + "ssl", + certfile, + ) + port = ast.literal_eval(p.attrib["port"]) + proxy_host = p.xpath("./proxy_host/text()")[0] + proxy_port = ast.literal_eval(p.xpath("./proxy_port/text()")[0]) + decoder = p.xpath("./decoder/text()") + if len(decoder) > 0: + decoder = decoder[0] + else: + decoder = None + proxy_instance = Proxy( + name, proxy_host, proxy_port, decoder, keyfile, certfile + ) + proxy_server = proxy_instance.get_server(host, port) + proxy_greenlet = spawn_startable_greenlet(proxy_server) + proxy_greenlet.link_exception(on_unhandled_greenlet_exception) + servers.append((proxy_instance, proxy_greenlet)) + else: + logger.info("Proxy available but disabled by template.") else: - # wait for the child to end - try: - os.waitpid(pid, 0) - except KeyboardInterrupt: - pass - # Revert MAC address - iface = config.get("change_mac_addr", "iface") - mac_addr.revert_mac(iface) + logger.info( + "No proxy template found. Service will remain unconfigured/stopped." + ) + + try: + if len(servers) > 0: + gevent.wait() + except KeyboardInterrupt: + logging.info("Stopping Conpot") + for server, greenlet in servers: + logging.debug(f"Shutting down {greenlet.name}") + server.stop() + greenlet.get() + finally: + conpot_core.close_fs() if __name__ == "__main__": diff --git a/conpot/testing.cfg b/conpot/testing.cfg index c1639226..84136296 100644 --- a/conpot/testing.cfg +++ b/conpot/testing.cfg @@ -45,8 +45,3 @@ use_https = False [fetch_public_ip] enabled = True urls = ["http://whatismyip.akamai.com/", "http://wgetip.com/"] - -[change_mac_addr] -enabled = False -iface = eth0 -addr = 00:de:ad:be:ef:00 diff --git a/conpot/tests/test_utils_mac_addr.py b/conpot/tests/test_utils_mac_addr.py deleted file mode 100644 index a53f9135..00000000 --- a/conpot/tests/test_utils_mac_addr.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (C) 2015 Adarsh Dinesh -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -import unittest -import conpot.utils.mac_addr as mac_addr -import subprocess - - -class TestMacAddrUtil(unittest.TestCase): - def setUp(self): - self.change_mac_process = subprocess.Popen( - ["ip", "li", "delete", "dummy", "type", "dummy"], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - - def tearDown(self): - self.change_mac_process.terminate() - - @unittest.skip("shunt to a later phase") - def test_mac(self): - """ - Objective: Test if the spoofer is able to change MAC address - """ - testmac = b"00:de:ad:be:ef:00" - iface = b"dummy" - # Load dummy module - s = subprocess.Popen( - ["modprobe", "dummy"], stderr=subprocess.STDOUT, stdout=subprocess.PIPE - ) - # Check if dummy is loaded - data = s.stdout.read() - if data: - self.skipTest("Can't create dummy device") - # Create a dummy network interface - subprocess.Popen( - ["ip", "li", "add", "dummy", "type", "dummy"], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - s = subprocess.Popen(["ip", "link", "show"], stdout=subprocess.PIPE) - data = s.stdout.read() - if b"dummy" in data: - # Change mac address of dummy interface and test it - mac_addr.change_mac(iface=iface, mac=testmac) - flag = mac_addr._check_mac(iface, testmac) - # Remove the dummy interface - with self.change_mac_process: - self.assertTrue(flag is True) - else: - self.skipTest("Can't change MAC address") diff --git a/conpot/utils/mac_addr.py b/conpot/utils/mac_addr.py deleted file mode 100644 index 2a30758d..00000000 --- a/conpot/utils/mac_addr.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (C) 2015 Adarsh Dinesh -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -import logging -import subprocess - -logger = logging.getLogger(__name__) - - -def _check_mac(iface, addr): - s = subprocess.Popen(["ifconfig", iface], stdout=subprocess.PIPE) - data = s.stdout.read() - if addr in data: - return True - else: - return False - - -def _is_dhcp(iface): - s = subprocess.Popen( - ["cat", "/var/lib/dhcp/dhclient.leases"], stdout=subprocess.PIPE - ) - data = s.stdout.read() - if iface in data: - return True - else: - return False - - -def _renew_lease(iface): - subprocess.Popen(["dhclient", "-r"], stdout=subprocess.PIPE) - subprocess.Popen(["dhclient", iface], stdout=subprocess.PIPE) - - -def change_mac(iface=None, mac=None, config=None, revert=None): - if config: - iface = config.get("change_mac_addr", "iface") - mac = config.get("change_mac_addr", "addr") - - # Changing MAC address and restarting network - subprocess.Popen( - ["ip", "link", "set", iface, "down"], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - subprocess.Popen( - ["ip", "link", "set", "dev", iface, "address", mac], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - subprocess.Popen( - ["ip", "link", "set", iface, "up"], - stderr=subprocess.STDOUT, - stdout=subprocess.PIPE, - ) - - if _check_mac(iface, mac): - if revert: - logger.info("MAC address reverted for interface %s", iface) - else: - logger.info("MAC address of interface %s changed %s", iface, mac) - if _is_dhcp(iface): - _renew_lease(iface) - logger.info("Interface has a DHCP lease, refreshed.") - else: - logger.warning("Could not change MAC address.") - - -def revert_mac(iface): - s = subprocess.Popen(["ethtool", "-P", iface], stdout=subprocess.PIPE) - mac = s.stdout.read().split(" ")[2].strip() - change_mac(iface, mac, revert=True)