Source code for bashfuscator.core.engine.mangler

"""
Class to manage obfuscation technuqies that are applied on all Mutators
"""
import re
import string

from bashfuscator.core.engine.random import RandomGen


[docs]class Mangler(object): """ Class to handle mangling of individual payload lines """ binaryRegexStr = r":\w+:" requiredWhitespaceRegexStr = r"\^ \^" optionalWhitespaceRegexStr = r"\? \?" requiredWhitespaceAndRandCharsRegexStr = "% %" optionalWhitespaceAndRandCharsRegexStr = r"\* \*" integerNoWrapperRegexStr = r"#\d+#" integerWithWrapperRegexStr = r"&\d+&" commandEndRegexStr = "END[01]?" binaryEscapedRegexStr = r"\\:\w+\\:" requiredWhitespaceEscapedRegexStr = r"\\\^ \\\^" optionalWhitespaceEscapedRegexStr = r"\\\? \\\?" requiredWhitespaceAndRandCharsEscapedRegexStr = r"\\% \\%" optionalWhitespaceAndRandCharsEscapedRegexStr = r"\\\* \\\*" integerNoWrapperEscapedRegexStr = r"\\#\d+\\#" integerWithWrapperEscapedRegexStr = r"\\&\d+\\&" binaryRegex = re.compile(binaryRegexStr) requiredWhitespaceRegex = re.compile(requiredWhitespaceRegexStr) optionalWhitespaceRegex = re.compile(optionalWhitespaceRegexStr) requiredWhitespaceAndRandCharsRegex = re.compile(requiredWhitespaceAndRandCharsRegexStr) optionalWhitespaceAndRandCharsRegex = re.compile(optionalWhitespaceAndRandCharsRegexStr) integerNoWrapperRegex = re.compile(integerNoWrapperRegexStr) integerWithWrapperRegex = re.compile(integerWithWrapperRegexStr) commandEndRegex = re.compile(commandEndRegexStr) boblRegexStr = "{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}".format( binaryRegexStr, requiredWhitespaceRegexStr, optionalWhitespaceRegexStr, requiredWhitespaceAndRandCharsRegexStr, optionalWhitespaceAndRandCharsRegexStr, integerNoWrapperRegexStr, integerWithWrapperRegexStr, commandEndRegexStr ) escapedBoblRegexStr = "{0}|{1}|{2}|{3}|{4}|{5}|{6}".format( binaryEscapedRegexStr, requiredWhitespaceEscapedRegexStr, optionalWhitespaceEscapedRegexStr, requiredWhitespaceAndRandCharsEscapedRegexStr, optionalWhitespaceAndRandCharsEscapedRegexStr, integerNoWrapperEscapedRegexStr, integerWithWrapperEscapedRegexStr ) boblRegex = re.compile(boblRegexStr) escapedBoblRegex = re.compile(escapedBoblRegexStr) completeBoblRegex = re.compile(f"{boblRegexStr}|{escapedBoblRegexStr}") def __init__(self): self.sizePref = None self.debug = None self.mangleBinaries = None self.binaryManglePercent = None self.randWhitespace = None self.randWhitespaceRange = None self.insertChars = None self.insertCharsRange = None self.misleadingCmds = None self.misleadingCmdsRange = None self.mangleIntegers = None self.expandIntegers = None self.randomizeIntegerBases = None self.integerExpansionDepth = None self.randomizeTerminators = None self.cmdTerminatorPos = 0 self.booleanCmdTerminator = False self.nonBooleanCmdTerminator = False self.extraJunk = "" self.cmdCounter = 0 self.cmdBufferOffset = None self.quoted = False self.terminatedCmdLast = False self.payloadLines = [] self.finalPayload = "" self.randGen = RandomGen() def _initialize(self, sizePref=None, enableMangling=None, mangleBinaries=None, binaryManglePercent=None, randWhitespace=None, randWhitespaceRange=None, insertChars=None, insertCharsRange=None, misleadingCmds=None, misleadingCmdsRange=None, mangleIntegers=None, expandIntegers=None, randomizeIntegerBases=None, integerExpansionDepth=None, randomizeTerminators=None, debug=None): self.sizePref = sizePref self.randGen.sizePref = self.sizePref self.extraJunk = "" self.payloadLines.clear() self.finalPayload = "" if debug: self.debug = debug else: self.debug = False if enableMangling is False: self.mangleBinaries = False self.randWhitespace = False self.insertChars = False self.misleadingCmds = False self.mangleIntegers = False self.randomizeTerminators = False return if mangleBinaries is not None: self.mangleBinaries = mangleBinaries else: self.mangleBinaries = True if binaryManglePercent: self.binaryManglePercent = binaryManglePercent else: if self.sizePref == 1: self.binaryManglePercent = 35 elif self.sizePref == 2: self.binaryManglePercent = 50 else: self.binaryManglePercent = 75 if randWhitespace is not None: self.randWhitespace = randWhitespace else: self.randWhitespace = True if randWhitespaceRange: self.randWhitespaceRange = randWhitespaceRange else: if self.sizePref == 1: self.randWhitespaceRange = (0, 2) elif self.sizePref == 2: self.randWhitespaceRange = (1, 3) else: self.randWhitespaceRange = (2, 5) if insertChars is not None: self.insertChars = insertChars else: self.insertChars = True if insertCharsRange: self.insertCharsRange = insertCharsRange else: if self.sizePref == 1: self.insertCharsRange = (0, 1) elif self.sizePref == 2: self.insertCharsRange = (1, 2) else: self.insertCharsRange = (1, 3) if misleadingCmds is not None: self.misleadingCmds = misleadingCmds else: self.misleadingCmds = True if misleadingCmdsRange: self.misleadingCmdsRange = misleadingCmdsRange else: if self.sizePref == 1: self.misleadingCmdsRange = (0, 1) elif self.sizePref == 2: self.misleadingCmdsRange = (1, 2) else: self.misleadingCmdsRange = (1, 3) if mangleIntegers is not None: self.mangleIntegers = mangleIntegers else: self.mangleIntegers = True if expandIntegers is not None: self.expandIntegers = expandIntegers else: self.expandIntegers = True if randomizeIntegerBases is not None: self.randomizeIntegerBases = randomizeIntegerBases else: self.randomizeIntegerBases = True if integerExpansionDepth: self.integerExpansionDepth = integerExpansionDepth else: if self.sizePref == 1: self.integerExpansionDepth = 1 elif self.sizePref == 2: self.integerExpansionDepth = 1 else: self.integerExpansionDepth = 2 if randomizeTerminators is not None: self.randomizeTerminators = randomizeTerminators else: self.randomizeTerminators = True
[docs] def addLinesInRandomOrder(self, payloadLines): """ Add lines contained in payloadLines to the final payload in a random order. :param payloadLines: sequence of lines to be added to the final payload. Can be a list, or a dict, with the keys being the lines to add, and the values being the data to add into the line after BOBL expansions are processed. :type payloadLines: list or dict """ if isinstance(payloadLines, list): self.randGen.randShuffle(payloadLines) for line in payloadLines: self.addPayloadLine(line) elif isinstance(payloadLines, dict): keys = list(payloadLines.keys()) self.randGen.randShuffle(keys) for line in keys: self.addPayloadLine(line, payloadLines[line])
[docs] def getMangledLine(self, payloadLine, inputChunk=None): """ Mangle a line, preform any final processing and return its output. :param payloadLine: line to be mangled. If the line contains more than 2 characters of unknown input data, 'DATA' should be substituted for where the input data should go, and the inputChunk parameter should contain the input data :type payloadLine: str :param inputChunk: unknown input data to be substituted into the line after it undergoes mangling :type inputChunk: str or None :returns: mangled line as str """ self.addPayloadLine(payloadLine, inputChunk) return self.getFinalPayload()
[docs] def addPayloadLine(self, payloadLine, inputChunk=None): """ Mangle a line and add it to the final payload. :param payloadLine: line to be mangled. If the line contains more than 2 characters of unknown input data, 'DATA' should be substituted for where the input data should go, and the inputChunk parameter should contain the input data :type payloadLine: str :param inputChunk: unknown input data to be substituted into the line after it undergoes mangling :type inputChunk: str or None """ mangledPayloadLine = self._mangleLine(payloadLine, inputChunk) self.payloadLines.append(mangledPayloadLine)
def _mangleLine(self, payloadLine, inputChunk=None): """ Return a mangled line. Should not be called directly, use :meth:`~Mangler.addPayloadLine` or :meth:`~Mangler.getMangledLine` instead. :param payloadLine: line to be mangled. If the line contains more than 2 characters of unknown input data, 'DATA' should be substituted for where the input data should go, and the inputChunk parameter should contain the input data :type payloadLine: str :param inputChunk: unknown input data to be substituted into the line after it undergoes mangling :type inputChunk: str or None :returns: mangled line as str """ mangledPayloadLine = payloadLine boblSyntaxMatch = Mangler.completeBoblRegex.search(mangledPayloadLine) while boblSyntaxMatch: if Mangler.boblRegex.match(boblSyntaxMatch.group()): if Mangler.binaryRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._mangleBinary(boblSyntaxMatch, mangledPayloadLine) elif Mangler.requiredWhitespaceRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._insertWhitespaceAndRandChars(boblSyntaxMatch, mangledPayloadLine, True, False) elif Mangler.optionalWhitespaceRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._insertWhitespaceAndRandChars(boblSyntaxMatch, mangledPayloadLine, False, False) elif Mangler.requiredWhitespaceAndRandCharsRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._insertWhitespaceAndRandChars(boblSyntaxMatch, mangledPayloadLine, True, True) elif Mangler.optionalWhitespaceAndRandCharsRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._insertWhitespaceAndRandChars(boblSyntaxMatch, mangledPayloadLine, False, True) elif Mangler.integerNoWrapperRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._mangleInteger(boblSyntaxMatch, mangledPayloadLine, False) elif Mangler.integerWithWrapperRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._mangleInteger(boblSyntaxMatch, mangledPayloadLine, True) elif Mangler.commandEndRegex.match(boblSyntaxMatch.group()): mangledPayloadLine, searchPos = self._getCommandTerminator(boblSyntaxMatch, mangledPayloadLine) # we're dealing with escaped BOBL syntax, we need to unescape it else: escapedData = mangledPayloadLine[boblSyntaxMatch.start() + 1:boblSyntaxMatch.end() - 2] + mangledPayloadLine[boblSyntaxMatch.end() - 1] mangledPayloadLine = mangledPayloadLine[:boblSyntaxMatch.start()] + escapedData + mangledPayloadLine[boblSyntaxMatch.end():] searchPos = boblSyntaxMatch.end() - 2 boblSyntaxMatch = Mangler.completeBoblRegex.search(mangledPayloadLine, pos=searchPos) if inputChunk: mangledPayloadLine = mangledPayloadLine.replace("DATA", inputChunk) return mangledPayloadLine
[docs] def addJunk(self, prependJunk=False): """ Add random whitespace and useless commands to the beginning or end of the final payload. :param prependJunk: True if junk should be added to beginning of payload :type prependJunk: bool """ randJunk = self._getWhitespaceAndRandChars(False, True) if prependJunk: self.finalPayload += randJunk else: self.extraJunk += randJunk
def _mangleBinary(self, binaryMatch, payloadLine): mangledBinary = "" ansiCQuotedChar = "" ansiCHex = False ansiCOctal = False lastCharNotMangled = False lastCharAnsiCQuoted = False hexValues = string.digits + "abcdef" binaryStr = payloadLine[binaryMatch.start() + 1:binaryMatch.end() - 1] if self.mangleBinaries: for char in binaryStr: if self.randGen.probibility(self.binaryManglePercent / 3): if self.randGen.probibility(50): mangledBinary += '""' else: mangledBinary += "''" lastCharAnsiCQuoted = False if self.randGen.probibility(self.binaryManglePercent): # if the current character is a digit, we can do integer mangling on it if char.isdigit() and self.mangleIntegers: choiceNum = 5 else: choiceNum = 4 choice = self.randGen.randChoice(choiceNum) if choice == 0: mangledBinary += "\\" + char lastCharAnsiCQuoted = False elif choice == 1: if self.randGen.probibility(50): mangledBinary += '"' + char + '"' else: mangledBinary += "'" + char + "'" lastCharAnsiCQuoted = False elif choice == 2: # if the last character wasn't mangled, and we are going to ANSI-C quote, we can shove the # previous character in the beginning of the expansion. ie a$'\x65' -> $'a\x65' if lastCharNotMangled and mangledBinary[-1] not in ["'", '"'] and self.randGen.probibility(self.binaryManglePercent): ansiCQuotedChar = self._getAnsiCQuotedStr(char) ansiCValue = ansiCQuotedChar[2:] mangledBinary = mangledBinary[:-1] + "$'" + mangledBinary[-1] + ansiCValue if ansiCValue[2] == "x": ansiCHex = True ansiCOctal = False elif ansiCValue[2] != "u" and ansiCValue[2] != "U": ansiCOctal = True ansiCHex = False else: ansiCHex = False ansiCOctal = False # if the last character was ANSI-C quoted, and we're going to do that again, we can just add # the new expansion as part of the previous one. ie $'\x65'$'\101' -> $'\x65\101' elif lastCharAnsiCQuoted and self.randGen.probibility(50): ansiCQuotedChar = self._getAnsiCQuotedStr(char) ansiCValue = ansiCQuotedChar[2:] mangledBinary = mangledBinary[:-1] + ansiCValue if ansiCValue[1] == "x": ansiCHex = True ansiCOctal = False elif ansiCValue[1] != "u" and ansiCValue[1] != "U": ansiCOctal = True ansiCHex = False else: ansiCHex = False ansiCOctal = False else: ansiCQuotedChar = self._getAnsiCQuotedStr(char) mangledBinary += ansiCQuotedChar if ansiCQuotedChar[3] == "x": ansiCHex = True ansiCOctal = False elif ansiCQuotedChar[3] != "u" and ansiCQuotedChar[3] != "U": ansiCOctal = True ansiCHex = False else: ansiCHex = False ansiCOctal = False lastCharAnsiCQuoted = True elif choice == 3: mangledBinary += self._getRandChars() + char lastCharAnsiCQuoted = False elif choice == 4: mangledBinary += self._getMangledInteger(int(char), True) lastCharAnsiCQuoted = False lastCharNotMangled = False else: # if the last character was ANSI-C quoted, we can show the current character into the # end of the last ANSI-C quoted expansion. ie $'\x65'y -> $'\x65y' appendChar = False if lastCharAnsiCQuoted: # make sure char to be appended won't be interpreted as hex; ie $'\x7' + a = $'\x7a' if ansiCHex and (len(ansiCQuotedChar) == 7 or char not in hexValues): appendChar = True # make sure char to be appended won't be interpreted as octal; ie $'\10' + 3 = $'\103' elif ansiCOctal and (len(ansiCQuotedChar) >= 7 or not (char.isdigit() and int(char) < 8)): appendChar = True elif not ansiCHex and not ansiCOctal: appendChar = True if appendChar and self.randGen.probibility(self.binaryManglePercent): mangledBinary = mangledBinary[:-1] + char + "'" lastCharNotMangled = False lastCharAnsiCQuoted = True else: mangledBinary += char lastCharNotMangled = True lastCharAnsiCQuoted = False else: mangledBinary = binaryStr mangledPayloadLine = payloadLine[:binaryMatch.start()] + mangledBinary + payloadLine[binaryMatch.end():] searchPos = len(payloadLine[:binaryMatch.start()] + mangledBinary) return mangledPayloadLine, searchPos def _getAnsiCQuotedStr(self, inStr): """ Return an Ansi-C quoted string. Apply longer forms of Ansi-C quoting depending on the user's sizePref. :param inStr: string to Ansi-C quote :type inStr: str :returns: Ansi-C quoted str """ if self.sizePref == 1: maxChoice = 2 elif self.sizePref == 2: maxChoice = 3 else: maxChoice = 4 encodedStr = "$'\\" for char in inStr: choice = self.randGen.randChoice(maxChoice) if choice == 0: encodedStr += oct(ord(char))[2:] + "\\" elif choice == 1: encodedStr += hex(ord(char))[1:] + "\\" elif choice == 2: encodedStr += "u00" + hex(ord(char))[2:] + "\\" else: encodedStr += "U000000" + hex(ord(char))[2:] + "\\" encodedStr = encodedStr[:-1] + "'" return encodedStr def _insertWhitespaceAndRandChars(self, whitespaceMatch, payloadLine, whitespaceRequired, insertRandChars): randCharsAndWhitespace = self._getWhitespaceAndRandChars(whitespaceRequired, insertRandChars) mangledPayloadLine = payloadLine[:whitespaceMatch.start()] + randCharsAndWhitespace + payloadLine[whitespaceMatch.end():] searchPos = len(payloadLine[:whitespaceMatch.start()] + randCharsAndWhitespace) return mangledPayloadLine, searchPos def _getWhitespaceAndRandChars(self, whitespaceRequired, insertRandChars): randCharsAndWhitespace = "" if not (insertRandChars and self.insertChars): randCharsAndWhitespace = self._getRandWhitespace(whitespaceRequired) elif insertRandChars and self.insertChars: charsInsertNum = self.randGen.randGenNum(self.insertCharsRange[0], self.insertCharsRange[1]) for i in range(charsInsertNum): if self.randWhitespace: randCharsAndWhitespace += self._getRandWhitespace(whitespaceRequired) randCharsAndWhitespace += self._getRandChars() randCharsAndWhitespace += self._getRandWhitespace(whitespaceRequired) return randCharsAndWhitespace def _getRandWhitespace(self, whitespaceRequired): if not self.randWhitespace: if whitespaceRequired: whitespaceAmount = 1 else: whitespaceAmount = 0 else: if whitespaceRequired and (not self.randWhitespaceRange or self.randWhitespaceRange[0] == 0): minSpace = 1 else: minSpace = self.randWhitespaceRange[0] whitespaceAmount = self.randGen.randGenNum(minSpace, self.randWhitespaceRange[1]) return " "*whitespaceAmount def _getRandChars(self): randChars = "" charsToEscape = "[]!(){}'`" + '"' varSymbol = self.randGen.randSelect(["@", "*"]) choice = self.randGen.randChoice(17) if self.quoted and choice == 2: while choice == 2: choice = self.randGen.randChoice(17) if varSymbol == "@" and choice != 2 and self.randGen.probibility(50): randChars = '"' self.quoted = True else: self.quoted = False if choice == 0: randChars += "$" + varSymbol elif choice == 1: randChars += f"${{{varSymbol}}}" elif choice == 2: randChars += f"${{!{varSymbol}}}" elif choice > 2 and choice <= 8: randParameterExpansionOperator = self.randGen.randSelect(["^", "^^", ",", ",,", "~", "~~"]) randChars += f"${{{varSymbol}{randParameterExpansionOperator}}}" elif choice > 8 and choice <= 14: randParameterExpansionOperator = self.randGen.randSelect(["#", "##", "%", "%%", "/", "//"]) randStr = self.randGen.randGenStr(escapeChars=charsToEscape, noBOBL=False) randStr = self._sanatizeExpansionString(randStr) randChars += f"${{{varSymbol}{randParameterExpansionOperator}{randStr}}}" else: randStr = self.randGen.randGenStr(escapeChars=charsToEscape, noBOBL=False) randStr = self._sanatizeExpansionString(randStr) randParameterExpansionOperator = self.randGen.randSelect(["/", "//"]) randStr2 = self.randGen.randGenStr(escapeChars=charsToEscape, noBOBL=False) randStr2 = self._sanatizeExpansionString(randStr2) randChars += f"${{{varSymbol}{randParameterExpansionOperator}{randStr}/{randStr2}}}" if self.quoted: randChars += '"' return randChars def _sanatizeExpansionString(self, exStr): oddSlashes = False for char in exStr[::-1]: if char == "\\": oddSlashes = not oddSlashes else: break if oddSlashes: exStr += "\\" return exStr def _mangleInteger(self, integerMatch, payloadLine, wrapExpression): integer = int(payloadLine[integerMatch.start() + 1:integerMatch.end() - 1]) mangledInt = self._getMangledInteger(integer, wrapExpression) mangledPayloadLine = payloadLine[:integerMatch.start()] + mangledInt + payloadLine[integerMatch.end():] searchPos = len(payloadLine[:integerMatch.start()] + mangledInt) return mangledPayloadLine, searchPos def _getMangledInteger(self, integer, wrapExpression): if self.mangleIntegers: if self.expandIntegers: mangledInt = self._expandInteger(integer, self.integerExpansionDepth) mangledInt = self._wrapArithmeticExpression(mangledInt) elif self.randomizeIntegerBases: mangledInt = self._getIntegerWithRandBase(integer) if wrapExpression: mangledInt = self._wrapArithmeticExpression(mangledInt) else: mangledInt = str(integer) else: mangledInt = str(integer) return mangledInt def _expandInteger(self, n, expansionDepth, randomizeBases=True): """ Generates a simple mathematical expression of 3 terms that equal the number passed. Returns a template expression string, and a tuple of the values of the terms in the generated expression. """ if type(n) == str: n = int(eval(n)) if n == 0: N = 0 while N == 0: N = self.randGen.randGenNum(-99999, 99999) else: N = n choice = self.randGen.randGenNum(0, 2) left = 0 if choice == 0: if N < 0: left = self.randGen.randGenNum(N * 2, -N + 1) right = self.randGen.randGenNum(N - 1, -N * 2) else: left = self.randGen.randGenNum(-N * 2, N - 1) right = self.randGen.randGenNum(-N + 1, N * 2) if left + right < n: offset = n - (left + right) expr = "(({0}+{1})+{2})" else: offset = (left + right) - n expr = "(-(-({0}+{1})+{2}))" elif choice == 1: if N < 0: left = self.randGen.randGenNum(N - 1, -N * 2) right = self.randGen.randGenNum(N * 2, N - 1) else: left = self.randGen.randGenNum(-N + 1, N * 2) right = self.randGen.randGenNum(-N * 2, N + 1) if left - right < n: offset = n - (left - right) expr = "(({0}-{1})+{2})" else: offset = (left - right) - n expr = "(-(-({0}-{1})+{2}))" elif choice == 2: if N < 0: left = self.randGen.randGenNum(int(N / 2), -int(N / 2)) right = self.randGen.randGenNum(int(N / 3), -int(N / 3)) else: left = self.randGen.randGenNum(-int(n / 2), int(n / 2)) right = self.randGen.randGenNum(-int(n / 3), int(n / 3)) if left * right < n: offset = n - (left * right) expr = "(({0}*{1})+{2})" else: offset = (left * right) - n expr = "(-(-({0}*{1})+{2}))" # Replace all zeros with an expression. Zeros make arithmetic easy if self.sizePref >= 2: if left == 0: left = self._expandInteger(0, 1, False) if right == 0: right = self._expandInteger(0, 1, False) if offset == 0: offset = self._expandInteger(0, 1, False) if expansionDepth > 1: if type(left) == str: left = int(eval(left)) if type(right) == str: right = int(eval(right)) if type(offset) == str: offset = int(eval(offset)) left = self._expandInteger(left, expansionDepth - 1) right = self._expandInteger(right, expansionDepth - 1) offset = self._expandInteger(offset, expansionDepth - 1) elif expansionDepth == 1 and randomizeBases and self.randomizeIntegerBases: if type(left) == str: left = int(eval(left)) if type(right) == str: right = int(eval(right)) if type(offset) == str: offset = int(eval(offset)) left = self._getIntegerWithRandBase(left) right = self._getIntegerWithRandBase(right) offset = self._getIntegerWithRandBase(offset) return expr.format(left, right, offset) def _getIntegerWithRandBase(self, integer): isNegative = False if integer < 0: integer = integer * -1 isNegative = True # choose a base that will obfuscate the integer better # when the integer is small. ie 7#4 is 4, too easy if 2 < integer and integer < 10: randBase = self.randGen.randGenNum(2, integer) else: randBase = self.randGen.randGenNum(2, 64) # make sure base isn't decimal while randBase == 10: randBase = self.randGen.randGenNum(2, 64) mangledInt = self._intToBaseN(randBase, integer) if isNegative: mangledInt = "-" + mangledInt if self.sizePref >= 2: moarMangledInt = "" for char in mangledInt: if self.randGen.probibility(33): if not self.insertChars or self.randGen.probibility(50): moarMangledInt += '"' + char + '"' else: moarMangledInt += self._getRandChars() + char else: moarMangledInt += char mangledInt = moarMangledInt return mangledInt def _intToBaseN(self, base, x): """ Borrowed from https://stackoverflow.com/questions/2267362/how-to-convert-an-integer-in-any-base-to-a-string """ baseCharList = string.digits + string.ascii_letters + "@" + "_" if x == 0: return str(base) + "#" + baseCharList[0] digits = [] while x: digits.append(baseCharList[x % base]) x = x // base digits.reverse() return str(base) + "#" + "".join(digits) def _wrapArithmeticExpression(self, expression): randWhitespace1 = self._getRandWhitespace(False) randWhitespace2 = self._getRandWhitespace(False) if self.randGen.probibility(50): wrappedExpr = f"$(({randWhitespace1}{expression}{randWhitespace2}))" else: wrappedExpr = f"$[{randWhitespace1}{expression}{randWhitespace2}]" return wrappedExpr def _getCommandTerminator(self, terminatorMatch, payloadLine): cmdReturnsTrue = False self.booleanCmdTerminator = False self.nonBooleanCmdTerminator = True if payloadLine[terminatorMatch.end() - 1].isdigit(): self.nonBooleanCmdTerminator = False if payloadLine[terminatorMatch.end() - 1] == "0": cmdReturnsTrue = True if self.debug: cmdTerminator = "\n" else: if self.cmdCounter == 0: self.cmdBufferOffset = self.randGen.randGenNum(1250, 1750) if self.cmdCounter == self.cmdBufferOffset: self.cmdCounter = 0 cmdTerminator = "\n" else: if self.randomizeTerminators and not self.nonBooleanCmdTerminator and self.randGen.probibility(50): self.booleanCmdTerminator = True if cmdReturnsTrue: cmdTerminator = "&&" else: cmdTerminator = "||" else: cmdTerminator = ";" self.cmdCounter += 1 self.cmdTerminatorPos = terminatorMatch.start() mangledPayloadLine = payloadLine[:terminatorMatch.start()] + cmdTerminator + payloadLine[terminatorMatch.end():] searchPos = len(payloadLine[:terminatorMatch.start()] + cmdTerminator) return mangledPayloadLine, searchPos
[docs] def getFinalPayload(self): """ Apply any final processing and return the final payload. """ finalJunk = "" # if the final cmd terminator of the payload is '&&' or '||', bash will throw errors if self.booleanCmdTerminator: if len(self.payloadLines[-1]) > self.cmdTerminatorPos + 2: finalJunk = self.payloadLines[-1][self.cmdTerminatorPos + 2:] self.payloadLines[-1] = self.payloadLines[-1][:self.cmdTerminatorPos] # randomly replace '&&' or '||' with ';' if self.randGen.probibility(50): self.payloadLines[-1] += ";" self.payloadLines[-1] += finalJunk # randomly remove the final command terminator elif not self.nonBooleanCmdTerminator and self.cmdTerminatorPos != 0 and self.randGen.probibility(50): if len(self.payloadLines[-1]) > self.cmdTerminatorPos + 1: finalJunk = self.payloadLines[-1][self.cmdTerminatorPos + 1:] self.payloadLines[-1] = self.payloadLines[-1][:self.cmdTerminatorPos] + finalJunk self.finalPayload += "".join(self.payloadLines) self.finalPayload += self.extraJunk return self.finalPayload