def _prepend(self, string): """Configure the `prepend` Transform, which prepends a static string to an arbitrary input. Args: string (str): The static string to be prepended. Raises: MalleableError: If `string` is null. """ if string is None: MalleableError.throw(Transform.__class__, "prepend", "string argument must not be null") self.transform = lambda data: string + data self.transform_r = lambda data: data[len(string):] self.generate_python = lambda var: "%(var)s=b'%(string)s'+%(var)s\n" % { "var": var, "string": string } self.generate_python_r = lambda var: "%(var)s=%(var)s[%(len)i:]\n" % { "var": var, "len": len(string) } self.generate_powershell = lambda var: "%(var)s='%(string)s'+%(var)s;" % { "var": var, "string": string } self.generate_powershell_r = lambda var: "%(var)s=%(var)s.substring(%(len)i,%(var)s.Length-%(len)i);" % { "var": var, "len": len(string) }
def _mask(self, key): """Configure the `mask` Transform, which encodes an arbitrary input using the XOR operation and a random key. Args: key (str): The key with which to encode / decode. Raises: MalleableError: If `key` is null or empty. """ if not key: MalleableError.throw(Transform.__class__, "mask", "key argument must not be empty") self.transform = lambda data: "".join( [chr(ord(c) ^ ord(key[0])) for c in data]) self.transform_r = self.transform self.generate_python = lambda var: "f_ord=ord if __import__('sys').version_info[0]<3 else int;%(var)s=''.join([chr(f_ord(_)^%(key)s) for _ in %(var)s])\n" % { "key": ord(key[0]), "var": var } self.generate_python_r = self.generate_python self.generate_powershell = lambda var: "%(var)s=[System.Text.Encoding]::Default.GetString($(for($_=0;$_ -lt %(var)s.length;$_++){[System.Text.Encoding]::Default.GetBytes(%(var)s)[$_] -bxor %(key)s}));" % { "key": ord(key[0]), "var": var } self.generate_powershell_r = self.generate_powershell
def _append(self, string): """Configure the `append` Transform, which appends a static string to an arbitrary input. Args: string (str): The static string to be appended. Raises: MalleableError: If `string` is null. """ if string is None: MalleableError.throw(Transform.__class__, "append", "string argument must not be null") self.transform = lambda data: data + string self.transform_r = lambda data: data[:-len(string)] self.generate_python = lambda var: "%(var)s+=b'%(string)s'\n" % { "var": var, "string": string } self.generate_python_r = lambda var: "%(var)s=%(var)s[:-%(len)i]\n" % { "var": var, "len": len(string) } self.generate_powershell = lambda var: "%(var)s+='%(string)s';" % { "var": var, "string": string } self.generate_powershell_r = lambda var: "%(var)s=%(var)s.Substring(0,%(var)s.Length-%(len)i);" % { "var": var, "len": len(string) }
def parameter(self, parameter): """Use the specified parameter to store the data after transformation. Args: parameter (str) Rasie: MalleableError: If `parameter` is empty. """ if not parameter: MalleableError.throw(Container, "parameter", "argument must not be null") self.terminator = Terminator(type=Terminator.PARAMETER, arg=parameter)
def header(self, header): """Use the specified header to store the data after transformation. Args: header (str) Rasie: MalleableError: If `header` is empty. """ if not header: MalleableError.throw(Container, "header", "argument must not be null") self.terminator = Terminator(type=Terminator.HEADER, arg=header)
def url(self, url): """Setter for the full url. Note: Actually sets parses the input into the urlparse.SplitResult _url. Args: url (str) """ if "://" in url: if "http://" not in url.lower() and "https://" not in url.lower(): MalleableError.throw(self.__class__, "url", "Scheme not supported: %s" % url) else: url = "http://" + url self._url = urlparse.urlsplit(url)
def ingest(self, file): """Ingest a profile file into the Profile object. Args: file (str): Filename to be read and parsed. """ if not file or not os.path.isfile(file): MalleableError.throw(self.__class__, "ingest", "Invalid file: %s" % str(file)) content = None with open(file) as f: content = f.read() if not content: MalleableError.throw(self.__class__, "ingest", "Empty file: %s" % str(file)) self._parse(self._pattern().searchString(content))
def _deserialize(cls, data): """Deserialize data into a Profile object. Args: data (dict (str, obj)): Serialized data (json) Returns: Profile object """ profile = super(Profile, cls)._deserialize(data) if data: try: profile.get = Get._deserialize(data["get"]) if "get" in data else Get() profile.post = Post._deserialize(data["post"] if "post" in data else Post()) profile.stager = Stager._deserialize(data["stager"] if "stager" in data else Stager()) profile.sleeptime = int(data["sleeptime"]) if "sleeptime" in data else 60000 profile.jitter = int(data["jitter"]) if "jitter" in data else 0 except Exception as e: MalleableError.throw(cls, "_deserialize", "An error occurred: " + str(e)) return profile
def generate_powershell_r(self, var): """Generate powershell code that would transform arbitrary data using the sequence of Transforms in reverse. Args: var (str): The variable name to be used in the powershell code. Returns: str: The powershell code. Raises: MalleableError: If `var` is empty. """ if not var: MalleableError.throw(Container, "generate_powershell_r", "var must not be empty") code = "" for t in self.transforms[::-1]: code += t.generate_powershell_r(var) return code
def host(self, host): """Setter for the host. Args: host (str) Raises: MalleableError: If scheme not supported. """ if "://" in host: if "http://" in host: host = host.lstrip("http://") self.scheme = "http" elif "https://" in host: host = host.lstrip("https://") self.scheme = "https" else: MalleableError.throw(self.__class__, "host", "Scheme not supported: %s" % host) if ":" not in host and self._url.port: host += ":" + str(self._url.port) self._url = self._url._replace(netloc=host)
def validate(self): """Validate the profile to verify it will succeed when used. Returns: bool: True if no checks fail. Raises: MalleableError: If a check fails. """ host = "http://domain.com:80" data = string.printable for format, p in [("base", self), ("clone", self._clone()), ("serialized", Profile._deserialize(self._serialize()))]: test = p.get.construct_client(host, data) clone = MalleableRequest() clone.url = test.url clone.verb = test.verb clone.headers = test.headers clone.body = test.body if self.get.extract_client(clone) != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-get-client-metadata" % format) test = p.get.construct_server(data) clone = MalleableResponse() clone.headers = test.headers clone.body = test.body if self.get.extract_server(clone) != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-get-server-output" % format) test = p.post.construct_client(host, data, data) clone = MalleableRequest() clone.url = test.url clone.verb = test.verb clone.headers = test.headers clone.body = test.body id, output = self.post.extract_client(clone) if id != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-post-client-id" % format) if output != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-post-client-output" % format) test = p.post.construct_server(data) clone = MalleableResponse() clone.headers = test.headers clone.body = test.body if self.post.extract_server(clone) != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-post-server-output" % format) test = p.stager.construct_client(host, data) clone = MalleableRequest() clone.url = test.url clone.verb = test.verb clone.headers = test.headers clone.body = test.body if self.stager.extract_client(clone) != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-stager-client-metadata" % format) test = p.stager.construct_server(data) clone = MalleableResponse() clone.headers = test.headers clone.body = test.body if self.stager.extract_server(clone) != data: MalleableError.throw(self.__class__, "validate", "Data-integrity check failed: %s-stager-server-output" % format) if set(self.get.client.uris).intersection(set(self.post.client.uris)) or \ set(self.post.client.uris).intersection(set(self.stager.client.uris)) or \ set(self.stager.client.uris).intersection(set(self.get.client.uris)) or \ len(self.get.client.uris + (self.post.client.uris if self.post.client.uris else ["/"])) == 0 or \ len(self.post.client.uris + (self.stager.client.uris if self.stager.client.uris else ["/"])) == 0 or \ len(self.stager.client.uris + (self.get.client.uris if self.get.client.uris else ["/"])) == 0 or \ ("/" in self.get.client.uris and len(self.post.client.uris) == 0) or \ ("/" in self.get.client.uris and len(self.stager.client.uris) == 0) or \ ("/" in self.post.client.uris and len(self.stager.client.uris) == 0) or \ ("/" in self.post.client.uris and len(self.get.client.uris) == 0) or \ ("/" in self.stager.client.uris and len(self.get.client.uris) == 0) or \ ("/" in self.stager.client.uris and len(self.post.client.uris) == 0): MalleableError.throw(self.__class__, "validate", "Cannot have duplicate uris: %s - %s - %s" % ( self.get.client.uris if self.get.client.uris else ["/"], self.post.client.uris if self.post.client.uris else ["/"], self.stager.client.uris if self.stager.client.uris else ["/"] )) return True