Unverified Commit b82193c1 authored by Nong Hoang Tu's avatar Nong Hoang Tu
Browse files

Bump project

parents
# Bashfuscator Contribution Guide
## Style Guide
### Bashfuscator conforms to the PEP8 standard except for a few key differences:
1. Class, function and variable names are camelCase, with class names starting with an uppercase letter. Constant variables are named the normal way, all uppercase with an '_' separating words in the name.
2. Four spaces should be used for indentation instead of tabs.
### Other miscellaneous style rules to follow:
- Always put whitespace between assignment, binary, comparison and Boolean operators:
```python
self.payload += "cat '" + self.workingDir + "'/" + "?" * cmdLogLen + ";" #good
self.payload+="cat '"+self.workingDir+"'/"+"?"*cmdLogLen+";" #not preferred
```
- Always put a blank line before the return statement of any returning function:
```python
def getPrefRange(self, pref):
if pref == 0:
min = max = 1
elif pref == 1:
min = 1
max = 2
elif pref < 4:
min = 1
max = pref + 2
else:
min = max = 5
return (min, max) #notice the blank line before the return
```
- Always put a space before and after parameters when passing multiple parameters to a function:
```python
prefStubs = self.getPrefItems(prefStubs, sizePref, timePref) #good
prefStubs = self.getPrefItems(prefStubs,sizePref,timePref) #not preferred
```
- Use double quotes for string whenever possible. Single quoted strings are acceptable if the string contains double quotes inside of it:
```python
if userOb.split("/")[0] == "command": #good
if userOb.split('/')[0] == 'command': #not preferred
self.payload += 'printf -- "\\x$(printf \'' + randomString #ok, string contains double quotes
```
- When adding imports to files, make sure the imports are alphabetical, and when possible import only what functions and classes that are needed.
```python
import binascii
from sys import exit #good
exit(0)
import sys #only needed to import sys.exit
import binascii #not in alphabetical order
sys.exit(0)
```
## Git Guidelines
- Commit early and often. More numerous, smaller commits are prefered to few large ones.
- Write meaningful commit messages. 'Misc tweaks' doesn't describe what was changed at all. When someone needs to go back and find that one commit that broke things, meaningful commit names make the process much less painful.
- Try to accomplish one main thing in each commit. Don't try to fix 5 issues in one commit, or add 3 features either.
MIT License
Copyright (c) 2018 capnspacehook
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
![Bashfuscator logo](img/bashfuscator_logo.png)
# Bashfuscator
[Documentation](https://bashfuscator.readthedocs.io/en/latest/index.html)
## What is Bashfuscator?
Bashfuscator is a modular and extendable Bash obfuscation framework written in Python 3. It provides numerous different ways of making Bash one-liners or scripts much more difficult to understand. It accomplishes this by generating convoluted, randomized Bash code that at runtime evaluates to the original input and executes it. Bashfuscator makes generating highly obfuscated Bash commands and scripts easy, both from the command line and as a Python library.
The purpose of this project is to give Red Team the ability to bypass static detections on a Linux system, and the knowledge and tools to write better Bash obfuscation techniques.
This framework was also developed with Blue Team in mind. With this framework, Blue Team can easily generate thousands of unique obfuscated scripts or commands to help create and test detections of Bash obfuscation.
### Media/slides
This is a list of all the media (i.e. youtube videos) or links to slides about Bashfuscator.
- [Bsides Charm](https://www.youtube.com/watch?v=zef422NDmpo)
### Payload support
Though Bashfuscator does work on UNIX systems, many of the payloads it generates will not. This is because most UNIX systems use BSD style utilities, and Bashfuscator was built to work with GNU style utilities. In the future BSD payload support may be added, but for now payloads generated with Bashfuscator should work on GNU Linux systems with Bash 4.0 or newer.
## Installation & Requirements
Bashfuscator requires Python 3.6+.
On a Debian-based distro, run this command to install dependencies:
`sudo apt-get update && sudo apt-get install python3 python3-pip python3-argcomplete xclip`
On a RHEL-based distro, run this command to install dependencies:
`sudo dnf update && sudo dnf install python3 python3-pip python3-argcomplete xclip`
Then, run these commands to clone and install Bashfuscator:
```bash
git clone https://github.com/Bashfuscator/Bashfuscator
cd Bashfuscator
python3 setup.py install --user
```
Only Debian and RHEL based distros are supported. Bashfuscator has been tested working on some UNIX systems, but is not supported on those systems.
## Example Usage
For simple usage, just pass the command you want to obfuscate with `-c`, or the script you want to obfuscate with `-f`.
```bash
$ bashfuscator -c "cat /etc/passwd"
[+] Mutators used: Token/ForCode -> Command/Reverse
[+] Payload:
${@/l+Jau/+<b=k } p''"r"i""n$'t\u0066' %s "$( ${*%%Frf\[4?T2 } ${*##0\!j.G } "r"'e'v <<< ' "} ~@{$" ") } j@C`\7=-k#*{$ "} ,@{$" ; } ; } ,,*{$ "}] } ,*{$ "} f9deh`\>6/J-F{\,vy//@{$" niOrw$ } QhwV#@{$ [NMpHySZ{$" s% "f"'"'"'4700u\n9600u\r'"'"'$p { ; } ~*{$ "} 48T`\PJc}\#@{$" 1#31 "} ,@{$" } D$y?U%%*{$ 0#84 *$ } Lv:sjb/@{$ 2#05 } ~@{$ 2#4 }*!{$ } OGdx7=um/X@RA{\eA/*{$ 1001#2 } Scnw:i/@{$ } ~~*{$ 11#4 "} O#uG{\HB%@{$" 11#7 "} ^^@{$" 011#2 "} ~~@{$" 11#3 } L[\h3m/@{$ "} ~@{$" 11#2 } 6u1N.b!\b%%*{$ } YCMI##@{$ 31#5 "} ,@{$" 01#7 } (\}\;]\//*{$ } %#6j/?pg%m/*{$ 001#2 "} 6IW]\p*n%@{$" } ^^@{$ 21#7 } !\=jy#@{$ } tz}\k{\v1/?o:Sn@V/*{$ 11#5 ni niOrw rof ; "} ,,@{$" } MD`\!\]\P%%*{$ ) }@{$ a } ogt=y%*{$ "@$" /\ } {\nZ2^##*{$ \ *$ c }@{$ } h;|Yeen{\/.8oAl-RY//@{$ p *$ "}@{$" t } zB(\R//*{$ } mX=XAFz_/9QKu//*{$ e *$ s } ~~*{$ d } ,*{$ } 2tgh%X-/L=a_r#f{\//*{$ w } {\L8h=@*##@{$ "} W9Zw##@{$" (=NMpHySZ ($" la'"'"''"'"'"v"'"'"''"'"''"'"'541\'"'"'$ } &;@0#*{$ ' "${@}" "${@%%Ij\[N }" ${@~~ } )" ${!*} | $@ $'b\u0061'''sh ${*//J7\{=.QH }
[+] Payload size: 1232 characters
```
You can copy the obfuscated payload to your clipboard with `--clip`, or write it to a file with `-o`.
For more advanced usage, use the `--choose-mutators` flag, and specify exactly what obfuscation modules, or Mutators, you want to use in what order. Use also the `-s` argument to control the level of obfuscation used.
```bash
bashfuscator -c "cat /etc/passwd" --choose-mutators token/special_char_only compress/bzip2 string/file_glob -s 1
[+] Payload:
"${@#b }" "e"$'\166'"a""${@}"l "$( ${!@}m''$'k\144'''ir -p '/tmp/wW'${*~~} ;$'\x70'"${@/AZ }"rin""tf %s 'MxJDa0zkXG4CsclDKLmg9KW6vgcLDaMiJNkavKPNMxU0SJqlJfz5uqG4rOSimWr2A7L5pyqLPp5kGQZRdUE3xZNxAD4EN7HHDb44XmRpN2rHjdwxjotov9teuE8dAGxUAL'> '/tmp/wW/?
??'; prin${@#K. }tf %s 'wYg0iUjRoaGhoNMgYgAJNKSp+lMGkx6pgCGRhDDRGMNDTQA0ABoAAZDQIkhCkyPNIm1DTQeppjRDTTQ8D9oqA/1A9DjGhOu1W7/t4J4Tt4fE5+isX29eKzeMb8pJsPya93' > '/tmp/wW/???
' "${@,, }" &&${*}pri''\n${*,}tf %s 'RELKWCoKqqFP5VElVS5qmdRJQelAziQTBBM99bliyhIQN8VyrjiIrkd2LFQIrwLY2E9ZmiSYqay6JNmzeWAklyhFuph1mXQry8maqHmtSAKnNr17wQlIXl/ioKq4hMlx76' >'/tmp/wW/??
';"${@, }" $'\x70'rintf %s 'clDkczJBNsB1gAOsW2tAFoIhpWtL3K/n68vYs4Pt+tD6+2X4FILnaFw4xaWlbbaJBKjbGLouOj30tcP4cQ6vVTp0H697aeleLe4ebnG95jynuNZvbd1qiTBDwAPVLTtCLx' >'/tmp/wW/?
?' ; ${*/~} p""${@##vl }ri""n''tf %s ' pr'"'"'i'"'"'$'"'"'n\x74'"'"'f %s "$( prin${*//N/H }tf '"'"'QlpoOTFBWSZTWVyUng4AA3R/gH7z/+Bd/4AfwAAAD8AAAA9QA/7rm7NzircbE1wlCTBEamT1PKekxqYIA9TNQ' >'/tmp/wW/????' "${@%\` }" ;p''r""i$'\x6e'''$'\164'"f" %s 'puxuZjSK09iokSwsERuYmYxzhEOARc1UjcKZy3zsiCqG5AdYHeQACRPKqVPIqkxaQnt/RMmoLKqCiypS0FLaFtirJFqQtbJLUVFoB/qUmEWVKxVFBYjHZcIAYlVRbkgWjh' >'/tmp/wW/?
' ${*};"p"rin''$'\x74f' %s 'Gs02t3sw+yFjnPjcXLJSI5XTnNzNMjJnSm0ChZQfSiFbxj6xzTfngZC4YbPvaCS3jMXvYinGLUWVfmuXtJXX3dpu379mvDn917Pg7PaoCJm2877OGzLn0y3FtndddpDohg'>'/tmp/wW/?
?
' && "${@^^ }" pr""intf %s 'Q+kXS+VgQ9OklAYb+q+GYQQzi4xQDlAGRJBCQbaTSi1cpkRmZlhSkDjcknJUADEBeXJAIFIyESJmDEwQExXjV4+vkDaHY/iGnNFBTYfo7kDJIucUES5mATqrAJ/KIyv1UV'> '/tmp/wW/
???' ${*^}; ${!@} "${@%%I }"pri""n$'\x74f' %s '1w6xQDwURXSpvdUvYXckU4UJBclJ4OA'"'"' |""b${*/t/\( }a\se$'"'"'6\x34'"'"' -d| bu${*/\]%}nzi'"'"'p'"'"'${!@}2 -c)" $@ |${@//Y^ } \ba\s"h" ' > '/tmp/wW/
??
' ${@%b } ; pr"i"\ntf %s 'g8oZ91rJxesUWCIaWikkYQDim3Zw341vrli0kuGMuiZ2Q5IkkgyAAJFzgqiRWXergULhLMNTjchAQSXpRWQUgklCEQLxOyAMq71cGgKMzrWWKlrlllq1SXFNRqsRBZsKUE' > '/tmp/wW/??
?'"${@//Y }" ;$'c\141t' '/tmp/wW'/???? ${*/m};"${@,, }" $'\162'\m '/tmp/wW'/???? &&${@^ }rmd\ir '/tmp/wW'; ${@^^ } )" "${@}"
[+] Payload size: 2062 characters
```
For more detailed usage and examples, please refer to the [documentation](https://bashfuscator.readthedocs.io/en/latest/Usage.html).
## Extending the Framework
Adding new obfuscation methods to the framework is simple, as Bashfuscator was built to be a modular and extendable framework. Bashfuscator's backend does all the heavy lifting so you can focus on writing robust obfuscation methods (documentation on adding modules coming soon).
## Authors and Contributers
- Andrew LeFevre ([capnspacehook](https://github.com/capnspacehook)): project lead and creator
- Charity Barker ([cpbarker](https://github.com/cpbarker)): team member
- Nathaniel Hatfield ([343iChurch](https://github.com/343iChurch)): writing the RotN Mutator
- Elijah Barker ([elijah-barker](https://github.com/elijah-barker)): writing the Hex Hash, Folder and File Glob Mutators
- Sam Kreischer: the awesome logo
## Credits
- [danielbohannon](https://github.com/danielbohannon), whose excellent [Invoke-Obfuscation](https://github.com/danielbohannon/Invoke-Obfuscation) and [Invoke-DOSfuscation](https://github.com/danielbohannon/Invoke-DOSfuscation) projects gave [capnspacehook](https://github.com/capnspacehook) the idea to start writing Bashfuscator, and insight on how to write robust obfuscation methods.
- [DissectMalware](https://github.com/DissectMalware), whose tweets on Bash obfuscation formed the backbone of some Mutators, and provided ideas for other obfuscation techniques.
- [ConsciousHacker](https://github.com/ConsciousHacker), whose insight and advice has helped the team greatly.
- Bash logo was originally from https://github.com/odb/official-bash-logo.
## Disclaimer
Bashfuscator was created for educational purposes *only*, use only on computers or networks you have explicit permission to do so. The Bashfuscator team is not responsible for any illegal or malicious acts preformed with this project.
#!/usr/bin/env python3
from argparse import ArgumentTypeError, ArgumentParser
from collections import OrderedDict
from subprocess import check_output, STDOUT, PIPE, Popen
import sys
import re
from argcomplete import autocomplete
import pyperclip
from bashfuscator.common.colors import bold, yellow
from bashfuscator.common.messages import activateQuietMode, printInfo, printWarning, printError, printExitMsg
from bashfuscator.core.engine.obfuscation_handler import ObfuscationHandler
from bashfuscator.core.utils import import_mutators
commandObfuscators, stringObfuscators, tokenObfuscators, encoders, compressors = import_mutators()
def check_positive(value):
ivalue = int(value)
if ivalue <= 0:
raise ArgumentTypeError(f"{ivalue} is an invalid positive int value")
return ivalue
def getMutators(prefix, parsed_args, **kwargs):
"""
Returns a list of all mutator's longName attribute for
auto-completion in cli
"""
mutatorNames = []
allMutators = commandObfuscators + stringObfuscators + tokenObfuscators + encoders + compressors
for mutator in allMutators:
mutatorNames.append(mutator.longName)
return mutatorNames
def getMutatorsAndStubs(prefix, parsed_args, **kwargs):
"""
Returns a list of all mutator's longName attribute, and every
longName attribute of each CommandObfuscator's stubs for
auto-completion in cli
"""
mutatorNames = []
for cmdOb in commandObfuscators:
for stub in cmdOb.stubs:
mutatorNames.append(cmdOb.longName + "/" + stub.longName)
mutators = stringObfuscators + tokenObfuscators + encoders + compressors
for mutator in mutators:
mutatorNames.append(mutator.longName)
return mutatorNames
def listMutators():
print(bold("Command Obfuscators:"))
listMutatorType(commandObfuscators)
print(bold("\nString Obfuscators:"))
listMutatorType(stringObfuscators)
print(bold("\nToken Obfuscators:"))
listMutatorType(tokenObfuscators)
print(bold("\nEncoders:"))
listMutatorType(encoders)
print(bold("\nCompressors:"))
listMutatorType(compressors)
def listMutatorType(mutators):
mutators.sort(key=lambda x: x.name)
for mutator in mutators:
print(bold(f"\nName: {mutator.name}"))
print(f"Description: {mutator.description}")
print(f"Size Rating: {mutator.sizeRating}")
print(f"Time Rating: {mutator.timeRating}")
if mutator.mutatorType != "command":
if mutator.binariesUsed:
binariesUsedString = "".join(b + ", " for b in mutator.binariesUsed)[:-2]
else:
binariesUsedString = "None"
print(f"Binaries used: {binariesUsedString}")
print(f"File write: {mutator.fileWrite}")
if mutator.notes is not None: print(f"Notes: {mutator.notes}")
if mutator.author is not None: print(f"Author: {mutator.author}")
if mutator.credits is not None:
print("Credits: ", end="")
for idx, credit in enumerate(mutator.credits):
if idx == 0:
print(credit)
else:
print(" "*9 + credit)
if mutator.mutatorType == "command":
print("\nStubs:")
for stub in mutator.stubs:
print(f"\n\tName: {stub.name}")
print(f"\tSize Rating: {stub.sizeRating}")
print(f"\tTime Rating: {stub.timeRating}")
print(f"\tFile write: {stub.fileWrite}")
if stub.binariesUsed:
binariesUsedString = "".join(b + ", " for b in stub.binariesUsed)[:-2]
else:
binariesUsedString = "None"
print(f"\tBinaries Used: {binariesUsedString}")
def printArgError(errorMsg):
print(f"bashfuscator: error: {errorMsg}")
sys.exit(1)
def checkArguments(args):
if not args.command and not args.file and not args.stdin:
parser.print_usage()
printArgError("one of the arguments -c/--command, -f/--file, or --stdin is required")
if args.quiet and args.test:
parser.print_usage()
printArgError("--test is not allowed with -q/--quiet")
if not args.no_mangling:
if not args.no_binary_mangling:
printWarning("--no-mangling implies --no-binary-mangling")
if not args.no_random_whitespace:
printWarning("--no-mangling implies --no-random-whitespace")
if not args.no_insert_chars:
printWarning("--no-mangling implies --no-insert-chars")
if not args.no_integer_mangling:
printWarning("--no-mangling implies --no-integer-mangling")
if not args.no_integer_expansion:
printWarning("--no-mangling implies --no-integer-expansion")
if not args.no_integer_base_randomization:
printWarning("--no-mangling implies --no-integer-base-randomization")
if not args.no_terminator_randomization:
printWarning("--no-mangling implies --no-terminator-randomization")
elif not args.no_integer_mangling:
if not args.no_integer_base_randomization:
printWarning("--no-integer-mangling implies --no-integer-base-randomization")
if not args.no_integer_expansion:
printWarning("--no-integer-mangling implies --no-integer-expansion")
if args.binary_mangle_percent:
if not args.no_mangling or not args.no_binary_mangling:
printWarning("binary mangling is disabled, --binary-mangle-percent argument will not take effect")
if args.random_whitespace_range:
if not args.no_mangling or not args.no_random_whitespace:
printWarning("random whitespace is disabled, --random-whitespace-range argument will not take effect")
else:
args.random_whitespace_range = checkRangeArgs("--random-whitespace-range", args.random_whitespace_range)
if args.insert_chars_range:
if not args.no_mangling or not args.no_insert_chars:
printWarning("random character insertion is disabled, --insert-char-range argument will not take effect")
else:
args.insert_chars_range = checkRangeArgs("--insert_chars_range", args.insert_chars_range)
if args.misleading_commands_range:
if not args.no_mangling or not args.no_misleading_commands:
printWarning("misleading command insertion is disabled, --misleading-commands-range argument will not take effect")
else:
args.misleading_commands_range = checkRangeArgs("--misleading_commands_range", args.misleading_commands_range)
if args.integer_expansion_depth:
if not args.no_mangling or not args.no_integer_mangling or not args.no_integer_expansion:
printWarning("integer arithmetic expansion is disabled, --integer-expansion-depth argument will not take effect")
def checkRangeArgs(argName, argValue):
if argValue.find(",") == -1:
printArgError(f"Invalid value for {argName} option: format is NUM,NUM")
rangeValues = *(int(x) for x in argValue.split(",")),
if rangeValues[0] < 0 or rangeValues[1] < 0:
printArgError(f"Invalid value for {argName} option: range values must be positive")
if rangeValues[1] == 0:
printArgError(f"Invalid value for {argName} option: upper bound must be greater than zero")
if rangeValues[0] > rangeValues[1]:
printArgError(f"Invalid value for {argName} option: invalid range")
return rangeValues
def printPayload(payload, args):
rows, columns = check_output(["stty", "size"]).decode().split()
rows = int(rows)
columns = int(columns)
printInfo("Payload:\n")
payloadLen = len(payload)
payloadPrintLen = int((rows * (columns * .50)) / 2)
payloadPrintLen = payloadPrintLen + (payloadPrintLen % columns)
if not args.quiet and (args.clip or args.outfile) and payloadLen > payloadPrintLen * 2:
# we don't need to print the whole payload, the user is given the full payload via a different method
# thanks Dbo for most of the logic and idea: https://github.com/danielbohannon/Invoke-Obfuscation
notShownMessageLen = len("[Not shown: characters]")
redactedLen = payloadLen - payloadPrintLen - notShownMessageLen
notShownMessage = yellow(f"[Not shown: {redactedLen + len(str(redactedLen))} characters]")
# make sure message is centered
notShownMsgCenteredIndex = int((columns - len(notShownMessage)) / 2)
notShownMsgCurrentIndex = payloadPrintLen % columns
if notShownMsgCurrentIndex > notShownMsgCenteredIndex:
payloadPrintLen = payloadPrintLen - (notShownMsgCurrentIndex - notShownMsgCenteredIndex)
else:
payloadPrintLen = payloadPrintLen + (notShownMsgCenteredIndex - notShownMsgCurrentIndex)
print(payload[:payloadPrintLen] + notShownMessage + payload[payloadLen - payloadPrintLen:])
else:
print(payload)
if not args.quiet:
print("")
printInfo(f"Payload size: {payloadLen} characters")
if __name__ == "__main__":
parser = ArgumentParser()
progOpts = parser.add_argument_group("Program Options")
inptOpts = progOpts.add_mutually_exclusive_group()
progOpts.add_argument("-l", "--list", action="store_true", help="List all the availible obfuscators, compressors, and encoders")
inptOpts.add_argument("-c", "--command", type=str, help="Command to obfuscate")
inptOpts.add_argument("-f", "--file", type=str, help="Name of the script to obfuscate")
inptOpts.add_argument("--stdin", action="store_true", help="Obfuscate stdin")
progOpts.add_argument("-o", "--outfile", type=str, help="File to write payload to")
progOpts.add_argument("-q", "--quiet", action="store_true", help="Print only the payload")
progOpts.add_argument("--clip", action="store_true", help="Copy the payload to clipboard")
progOpts.add_argument("--test", action="store_true", help="Test the payload after running it. Not compatible with -q")
obOpts = parser.add_argument_group("Obfuscation Options")
obOpts.add_argument("-s", "--payload-size", default=2, type=int, choices=range(1, 4), help="Desired size of the payload. Default: 2")
obOpts.add_argument("-t", "--execution-time", default=2, type=int, choices=range(1, 4), help="Desired speed of the payload. Default: 2")
obOpts.add_argument("--layers", type=check_positive, help="Number of layers of obfuscation to apply. Default is 1 when --choose-mutators is used, otherwise: 2")
binOpts = obOpts.add_mutually_exclusive_group()
binOpts.add_argument("--include-binaries", nargs="+", type=str, metavar="BINARIES", help="Binaries you exclusively want used in the generated payload")
binOpts.add_argument("--exclude-binaries", nargs="+", type=str, metavar="BINARIES", help="Binaries you don't want to be used in the generated payload")
obOpts.add_argument("--no-file-write", action="store_false", help="Don't use obfuscators that require writing to files")
obOpts.add_argument("--write-dir", default="/tmp/", type=str, help="Directory to use if Mutators need to write to or create files")
advancedOpts = parser.add_argument_group("Advanced Options")
chooseOpts = advancedOpts.add_mutually_exclusive_group()
chooseOpts.add_argument("--choose-mutators", nargs="+", metavar="MUTATOR", help="Manually choose what mutators are used in what order").completer = getMutators
chooseOpts.add_argument("--choose-all", nargs="+", metavar="MUTATOR", help="Manually choose what mutators and their stubs if applicable").completer = getMutatorsAndStubs
advancedOpts.add_argument("--no-mangling", action="store_false", help="Don't preform binary mangling and don't insert random whitespace and characters")
advancedOpts.add_argument("--no-binary-mangling", action="store_false", help="Don't obfuscate binary/builtin names")
advancedOpts.add_argument("--binary-mangle-percent", type=int, choices=range(1, 101), metavar="{1..100}", help="Percentage of chars of binary/builtin names to mangle")
advancedOpts.add_argument("--no-random-whitespace", action="store_false", help="Don't randomly add whitespace")
advancedOpts.add_argument("--random-whitespace-range", type=str, metavar="NUM,NUM", help="The range of random whitespace to add")
advancedOpts.add_argument("--no-insert-chars", action="store_false", help="Don't randomly add variables and characters that Bash ignores")
advancedOpts.add_argument("--insert-chars-range", type=str, metavar="NUM,NUM", help="The range of random variables and characters to add")
advancedOpts.add_argument("--no-misleading-commands", action="store_false", help="Don't randomly insert misleading commands that do nothing. NOT YET IMPLEMENTED")
advancedOpts.add_argument("--misleading-commands-range", type=str, metavar="NUM,NUM", help="The range of random misleading commands to add. NOT YET IMPLEMENTED")
advancedOpts.add_argument("--no-integer-mangling", action="store_false", help="Don't expand integers into arithmetic expressions with multiple number bases")
advancedOpts.add_argument("--no-integer-expansion", action="store_false", help="Don't expand integers into arithmetic expressions")
advancedOpts.add_argument("--no-integer-base-randomization", action="store_false", help="Don't randomize the number bases of integers")
advancedOpts.add_argument("--integer-expansion-depth", type=check_positive, help="Number of times to recursively expand integers into arithmetic expansions")
advancedOpts.add_argument("--no-terminator-randomization", action="store_false", help="Don't randomize the symbols that terminate commands")
advancedOpts.add_argument("--full-ascii-strings", action="store_true", help="Use the full ASCII character set (with a few exceptions) when generating random strings")
debugOpts = parser.add_argument_group("Debugging Options")
debugOpts = debugOpts.add_argument("--debug", action="store_true", help="Automatically terminate every command in the payload with a newline for easier payload debugging")
autocomplete(parser)
args = parser.parse_args()
if args.list:
listMutators()
exit(0)
if args.quiet:
activateQuietMode()
checkArguments(args)
if args.layers is None:
if args.choose_mutators is not None or args.choose_all is not None:
args.layers = 1
else:
args.layers = 2
if args.include_binaries is not None:
args.binaryPref = (args.include_binaries, True)
elif args.exclude_binaries is not None:
args.binaryPref = (args.exclude_binaries, False)
else:
args.binaryPref = None
shebang = "#!/bin/bash\n"
if args.stdin:
args.command = sys.stdin.read()
sys.stdin.close()
elif args.file:
with open(args.file, "rb") as infile:
firstLine = infile.readline().decode("utf-8")
if re.match(r"\s*#!", firstLine) is not None:
shebang = firstLine
else:
infile.seek(0)
args.command = infile.read().decode("utf-8")
if args.write_dir[-1:] != "/":
args.write_dir += "/"
obHandler = ObfuscationHandler(commandObfuscators, stringObfuscators, tokenObfuscators, encoders, compressors, args)
try:
payload = obHandler.generatePayload()
except KeyboardInterrupt:
printExitMsg("\nCtrl-C caught... stopping payload generation...")
if not args.choose_mutators and not args.choose_all:
mutatorChainStr = "Mutators used: "
for mutator in obHandler.mutatorList:
mutatorChainStr += f"{mutator.mutatorType.title()}/{mutator.name} -> "
mutatorChainStr = mutatorChainStr[:-4]
printInfo(mutatorChainStr)
if args.outfile:
with open(args.outfile, "wb") as outfile:
outfile.write(shebang.encode("utf-8"))
outfile.write(payload.encode("utf-8"))
printInfo(f"Payload written to {args.outfile}")
if args.clip:
pyperclip.copy(payload)
printInfo("Payload copied to clipboard")
printPayload(payload, args)
if args.test:
try:
printInfo("Testing payload:\n")
if args.outfile:
proc = Popen(["bash", args.outfile], stdout=PIPE, stderr=STDOUT, shell=False, universal_newlines=True)
stdout, __ = proc.communicate()
print(stdout)
else:
proc = Popen(payload, executable="bash", stdout=PIPE, stderr=STDOUT, shell=True, universal_newlines=True)
stdout, __ = proc.communicate()
print(stdout)
except KeyboardInterrupt:
printExitMsg("\nCtrl-C caught... stopping payload testing...")
# Copyright (C) 2010-2013 Claudio Guarnieri.
# Copyright (C) 2014-2016 Cuckoo Foundation.
"""
Provides helper functions for pretty-printing with colors. This file is
borrowed from the Cuckoo Sandbox Project:
https://github.com/cuckoosandbox/cuckoo
"""
import os
import sys