Skip to content

Using boko As A Class

Jesse edited this page May 23, 2020 · 5 revisions

boko stores all data in a dictionary for parsing. I wanted to keep all information usable in case someone wanted to hook into it for their own purposes.

To utilize this dictionary the boko class first needs to be imported, initialized, and run.

Initialization

When initializing boko, you need to give it a Boolean value for verbosity and sipdisabled.

verbosity will affect how it outputs to the standard output of your terminal.

  • True will output everything boko discovers to standard out.
  • False will only output Definite certainty vulnerabilities.

sipdisabled can be used if you would like to scan all files on the system including directories that are read-only because of SIP by default. This should only be used if SIP is disabled on the system.

  • True will scan all files on the system and ignore Read-Only default directories. The scanner will still check whether or not the user context has read or write permissions to a file or hijackable path.
  • False will ignore Read-Only default directories and system binaries when performing any of the scan options. Additionally, this will take the fact that a file is in a Read-Only directory to calculate certainty that the current user can exploit the vulnerability.

Below is an example of initializing the class:

import boko
verbosity = True
sipdisabled = False
bokoscanner = ExecutableScanner(verbosity, sipdisabled)

Discovery scan functions

Next, you can choose the type of scan you want to perform. The base information discovered here is stored within a dictionary. This information consists of the filepath as the dictionary key, whether or not the file is writable under the current user context, the filename, the filetypeh if it is an interesting file, whether or not it will parse the file, and set the mode key as "Passive" for the time being.

  • The loadedBinaries function will scan all currently running binaries. If sipdisabled is set to True this will scan all binaries running (not recommended), otherwise this function will scan everything running except for system binaries.
bokoscanner.loadedBinaries()
  • The installedBinaries function will scan a given directory for any executable and interesting files. Typically, it will take a specific path as a string argument to declare a path. If the path is omitted, it scans all files on the system starting at /.
# example to scan a specific directory
path = "/Applications/Numbers.app"
bokoscanner.installedBinaries(path)

# example to scan all files on the file-system starting at /
bokoscanner.installedBinaries()

File parsing function

Once one or all of the scan types are selected, boko needs to parse the files discovered for executables, scripts, and dylibs with the parseExecutables function. This function will only read files to view file headers and does not perform any execution. This will store additional dictionary items under the main filepath key. If the file is an executable boko will store load command information under the load key, including LC_RPATHs as a list, LC_LOAD_WEAK_DYLIBs as a list, and LC_LOAD_DYLIBs as a list; boko will also create a vulnerable placeholder key for scripts and binaries; and finally store the filetype if it is a binary and the human readable file type as filetypeh under the main filepath key.

bokoscanner.parseExecutables()

Processing functions

After the files discovered are parsed as executables, scripts, and other interesting files. You'll want to process the data. Here there are a few methods: processBinariesPassive, processBinariesActive, ProcessScriptBackdoors, and ProcessInterestingFiles. This is where boko will store vulnerability information on the files it processes. Under the vulnerable key these functions will store a list of dictionaries within the WeakDylib, DylibHijack, and BackdoorableScript keys. The dictionaries in these lists will store the Certainty of the vulnerability, the hijackPath path to use to exploit the vulnerability, the WriteAccess of the hijackable path, the LoadOrder of the rpath that is expanded, and whether or not the hijack path is within a SIP ReadOnlyPartition.

  • The processBinariesPassive function will only process the executable and dylib information that was discovered through parsing based on the file type header.
bokoscanner.processBinariesPassive()
  • The processBinariesActive function will parse the discovered files for anything that has the 'MH_EXECUTE' indicator in the file header. Once the binary is deemed a main executable, this function will the execute the binary for 3 seconds to scrape the rpaths that fail to expand. This only gives "Definite" certainty results, but may cause issues on the system if more than one program directory is chosen with the installedBinaries, even more so if a directory is omitted, because it will execute every executable file on the system (not recommended). One added feature here is that an additional dictionary key execution will be added to the main filepath key, which contains any standard and error output from executing the binaries. If verbose is True this will also get output to the command line.
bokoscanner.processBinariesActive()
  • The ProcessScriptBackdoors function will just do additional processing of the scripts and populate potential vulnerability information to the BackdoorableScript key.
bokoscanner.ProcessScriptBackdoors()
  • The ProcessInterestingFiles functions only use is to output interesting files to standard output, since all the data is already stored in the dictionary.
bokoscanner.ProcessInterestingFiles()

Getting the dictionary

Finally, once all the processing is complete you may access the dictionary with the GetResults function. You could technically use this function any time after the scanner is initialized, but it will be missing pieces of information.

results = bokoscanner.GetResults()

Dictionary format

filepath: { # Full file path of file that was parsed
  'writeable': Bool, # indicates whether or not the current user that ran the tool has write permissions on the file
  'execution': { # dictionary for execution output, only applicable if the --active or --both flag is used
      'standardoutput': [], # standard output from executing the binary
      'erroroutput' [] # standard error output from executing the binary, this will include the debug rpath information
   },
  'load': { # if a file is deemed an executable type this is created
      'LC_RPATHs': [], # a list of all load command rpaths
      'LC_LOAD_WEAK_DYLIBs': [], # a list of all load command weak dylibs
      'LC_LOAD_DYLIBs': [] # a list of all loaded dylibs
   },
  'filetypeh': 'String', # indicates the file type as a string : Executable, Dylib, Bundle, KextBundle, Script, Misc (based on file extension)
  'filetype': mach_header filetype, # only stored for executable file types
  'parse': 'String', # indicates if the file was an executable and was parsed for weaknesses
  'filename': 'String', # File name without full path
  'vulnerable': {
      'WeakDylib': [ # list of weak dylibs, each weak dylib has its own dictionary
          {
              'Certainty': 'String', # indicates how certain the vulnerability exists based on load path ordering and file type : Definite, High, Potential, Low
              'hijackPath': 'String', # full path a malicious dylib can be placed to hijack the load order of the base file
              'WriteAccess': Bool, # indicates whether or not the current user that ran the tool can write to the hijackPath
              'LoadOrder': int, # indicates the order in which the main binary Filename loads the dylib relative path, starts at 0
              'ReadOnlyPartition': Bool # indicates whether or not the directory is in a SIP-protected partition
          }
       ],
      'DylibHijack': [ # list of hijackable dylibs, each dylib has its own dictionary
          {
              'Certainty': 'String', # indicates how certain the vulnerability exists based on load path ordering and file type : Definite, High, Potential, Low
              'hijackPath': 'String', # full path a malicious dylib can be placed to hijack the load order of the base file
              'WriteAccess': Bool, # indicates whether or not the current user that ran the tool can write to the hijackPath
              'LoadOrder': int, # indicates the order in which the main binary Filename loads the dylib relative path, starts at 0
              'ReadOnlyPartition': Bool # indicates whether or not the directory is in a SIP-protected partition
          }
       ],
      'BackdoorableScript': [ # list of potentially backdoorable scripts, each script has its own dictionary
          {
              'Certainty': 'String', # indicates how certain the vulnerability exists based on load path ordering and file type : Definite, High, Potential, Low
              'hijackPath': 'String', # full path a malicious dylib can be placed to hijack the load order of the base file
              'WriteAccess': Bool, # indicates whether or not the current user that ran the tool can write to the hijackPath
              'LoadOrder': int, # indicates the order in which the main binary Filename loads the dylib relative path, starts at 0
              'ReadOnlyPartition': Bool # indicates whether or not the directory is in a SIP-protected partition
          }
       ]
   }
}

Clone this wiki locally