Skip to content

3. Templates

Tom S edited this page Aug 29, 2024 · 2 revisions

Templates and Links

All templates are JSON files. Android templates have four main sections (i.e., first level keys):

  1. METADATA
  2. MANIFESTPARAMS
  3. CODEPARAMS
  4. GRAPH

The METADATA section AND at least one of MANIFESTPARAMS and CODEPARAMS are required. The GRAPH section is required if the output is to be presented in a neo4j/visjs graph.

Each section is described in detail below. See Sample Template for, well, a sample template, with an explanation of the various sections. See Links for information on linking bugs together to create exploit chains. See Tips for some suggestions for creating good templates.

Important note: every keyword specified here is case-sensitive.

Even more important: the templates that have been included with Jandroid can probably be improved upon by someone with better knowledge of logic bugs. Use them only after checking that they serve your purpose.

METADATA

This has one required parameter, NAME, which must be a unique name for the bug/template. If more than one template uses the same name, then an error will be thrown and the second (and subsequent) templates with the same name will be ignored.

Do not use any name ending with "Start" or "End" as a template name. These are used for identifying start and end nodes in trace chains.

MANIFESTPARAMS

An object used for specifying requirements of AndroidManifest files. It has the following subkeys:

  • BASEPATH: string. Only present at the root level of the MANIFESTPARAMS object. It specifies the starting level for the search. Can have multiple options separated by OR. If this value is specified, then the manifest analysis will start from the specified point rather than from the root. e.g., a BASEPATH of manifest->application->activity would skip the levels corresponding to manifest and application and start directly from the activity level.
  • SEARCHPATH: object. Only present at the root level of the MANIFESTPARAMS object. Specifies the path to take within the manifest tree. Must follow the structure of the AndroidManifest.xml (including similar nesting). See the sample template on this page for an idea of the structure of this key. Any level within this key can have LOOKFOR and/or RETURN keys.
  • LOOKFOR: object. Can be present at any level within the SEARCHPATH or root. Has one or more of the following keys:
    • TAGEXISTS: string or list. String can specify a single tag to match, or ONE (or more) OF a number of tags separated by "OR". If ALL OF a number of tags are to be matched, they should be specified as individual elements within a list.
    • TAGNOTEXISTS: string or list. String can specify a single tag to match. String CANNOT have multiple options separated by "OR". If ALL OF a number of tags are to be matched, they should be specified as individual elements within a list.
    • TAGVALUEMATCH: string or list. String can specify a single value to match, or at least ONE OF a number of values separated by "OR". Note that you cannot specify a number of tag-value pairs within an "OR" clause; you can only specify a number of possible values corresponding to a single tag. If ALL of a number of tags are to be matched, they should be specified as individual elements within a list.
    • TAGVALUENOMATCH: string or list. String can specify a single tag to match. String CANNOT have multiple options separated by "OR". If ALL OF a number of tags are to be matched, they should be specified as individual elements within a list. At least one tag must have a value that is not equal to the string or list.
  • RETURN: string or list. Can be present at any level within the SEARCHPATH or root. String specifies a single return item. List specifies multiple. A RETURN item must have a unique identifier specified after the AS keyword. The identifier must begin with an @. The returned value can be graphed or used in subsequent searches (within the same bug template). See the section on RETURNs for more information.

NOTES:

  • RETURN can be present at multiple levels, but cannot be a subkey of a LOOKFOR object.
  • LOOKFOR can also be present at multiple levels, but cannot be a subkey of a LOOKFOR or RETURN object.
  • A RETURN will return tag values for the level at which it is specified.
  • If the RETURNed item is an activity name that is to be used in code searches, then specify that it is to be converted to smali representation using the <smali>: modifier.
  • If using a LOOKFOR and RETURN at the same level, make sure the LOOKFOR is specified first.

back to top

CODEPARAMS

An object used for specifying parameters for code searches/traces. Contains one or both of the following subkeys: SEARCH and TRACE.

  • SEARCH: a single search can be specified as a dictionary object. Multiple searches (all of which must be satisfied) can be specified as a list of objects. The objects must have one or more of the following keys:
    • SEARCHFORMETHOD: object. Look for existence of method.
      • METHOD (Required): string. Method of interest. See rules for TRACEFROM below.
    • SEARCHFORCALLTOMETHOD: object. Look for existence of calls to this method. Possible subkeys:
      • METHOD (Required): string. Method of interest. See rules for TRACEFROM below.
      • SEARCHLOCATION: string. Used to determine whether the call to the method was from a specific class or method.
      • RETURN: string. Of the format "x AS y", where x is one of <class> or <method>, indicating the class or method from which this method was called, and y is a (unique) identifier. The identifier must begin with @. This value can be graphed or used in subsequent searches (within the same bug template). See the section on RETURNs for more information.
    • SEARCHFORCLASS: object. Look for existence of class.
      • CLASS (Required): string. Class of interest. See rules for TRACEFROM below.
    • SEARCHFORCALLTOCLASS: object. Look for existence of calls to this class. Possible subkeys:
      • CLASS (Required): string. Class of interest. See rules for TRACEFROM below.
      • SEARCHLOCATION: string. Used to determine whether the call to the method was from a specific class or method.
      • RETURN: string. Of the format "x AS y", where x is one of <class> or <method>, indicating the class or method from which this method was called, and y is a (unique) identifier. The identifier must begin with @. This value can be graphed or used in subsequent searches (within the same bug template). See the section on RETURNs for more information.
    • SEARCHFORSTRING: object. Look for existence of string.
      • STRING (Required): string. String to search for.
    • SEARCHFORCALLTOSTRING: object. Look for existence of calls to this class. Possible subkeys:
      • STRING (Required): string. String to search for.
      • SEARCHLOCATION: string. Used to determine whether the call to the method was from a specific class or method.
      • RETURN: string. Of the format "x AS y", where x is one of <class> or <method>, indicating the class or method from which this method was called, and y is a (unique) identifier. The identifier must begin with @. This value can be graphed or used in subsequent searches (within the same bug template). See the section on RETURNs for more information.
    • SEARCHFORANNOTATION: object. Look for a method annotation
      • ANNOTATION (Required): string. Annotation to search for.
      • SEARCHLOCATION: string. Used to determine whether the annotated method was from a specific class or method.
      • RETURN: string. Of the format "x AS y", where x is one of <class> or <method>, indicating the class or method from which this method was called, and y is a (unique) identifier. The identifier must begin with @. This value can be graphed or used in subsequent searches (within the same bug template). See the section on RETURNs for more information.
  • TRACE: single trace requires object. Multiple traces (all of which must be satisfied) can be specified as list of objects. Object subkeys:
    • TRACEFROM (Required): string. Starting point in smali representation or linked items, or combination thereof. String can specify multiple possible classes/methods separated by the OR keyword. If we are tracing from a previously RETURNed value, then we can specify sub-parts by using []. That is, if a method is returned and we want to use only the class part for the TRACEFROM, then we can specify this as @prev_return[<class>]. If the entire value is to be used, we still need to use [] as @prev_return[].
    • TRACETO (Required): string. As for TRACEFROM.
    • TRACEDIRECTION: string. Must be either FORWARD or REVERSE, depending on how you want data to be traced. Default is REVERSE.
    • TRACELENGTHMAX: integer. Specifies the maximum length for a trace chain/path. Overrides the value in the config file for this trace object only.
    • RETURN: string. If specified, must be of the format <tracepath> AS @tracepath_<unique_identifier>. See the section on RETURNs for more information.
    • TRACETYPE (Experimental): string. One of BASIC or ADVANCED. If the type is ADVANCED, then the following additional keywords can be used with the TRACEFROM and TRACETO options. Default BASIC.
      • ARGTO: Trace to/from the argument to a function.
      • ARGINDEX: Only valid if ARGTO is specified. Index of the register used as an argument to the function of interest. Default 0.
      • RESULTOF: Trace to/from the output of a function.
      • A valid TRACEFROM/TRACETO string in ADVANCED trace mode could be:
        ARGTO <method>:Landroid/webkit/WebView;->loadUrl(Ljava/lang/String;)V ARGINDEX 1 or
        RESULTOF Landroid/content/Intent;->getData()Landroid/net/Uri;
    • Note: Forward tracing can only begin from a RESULTOF and can end in ARGTO or general method. Reverse tracing starts with an ARGTO and ends in RESULTOF or general method.
    • Note: Forward tracing can take a very long time in some cases. Opt for reverse tracing wherever possible.

back to top

GRAPH

A string used for specifying graphable elements. All elements must be the result of the preceding analysis.

A graphable template string is of the format
x WITH a AS attribute=p, b AS label, c AS attribute=r ...

  • Here, x is the element that is graphed. It must be a linked item. There are a number of possibilities:
    • x = "@tracepath_xx": this would graph an entire chain. Note that @tracepath_xx must be the identifier of a returned tracepath.
    • x = "@app": this would return a single node with the application package name.
    • x is something else beginning with @: any previously declared identifier output from a RETURN element.
  • The remaining are attributes and labels.
    • Attributes are specified as <value> AS attribute=<attribute_name>.
    • Labels are specified as <value> AS label.
  • p is a special type of attribute. It is the node identifier, which is an attribute that must be present for every node. The node identifier can be thought of as being similar to a primary key in a SQL database.
  • a tells the graphing tool which aspect of x to use as the node identifier. This can have a value of <self>, which would return the value of x as-is. It can also be any pattern created using <class>, <method> and <desc>. For example, if a is specified as <method>-<desc>-<class>, then the method call Lcom/xxxx/yyyy/zzzz;-><init>()V would be rendered as <init>-()V-Lcom/xxxx/yyyy/zzzz;.

You can have as many attributes and labels as you like for a graphable element (subject to any restrictions imposed by Neo4j). However, fewer is generally better. Also, it's easier if none but the first attribute/label is a linked element. If other attributes are linked, they will simply be added as a list to a single node (which can make everything look a bit untidy).

back to top

NOTES

RETURNs

RETURNs are items that are output from a particular analysis block. While the rules for RETURNs differ based on the type of analysis (i.e., Manifest vs. Code Search vs. Code Trace), there are some elements that all RETURNs have in common.

General Rules for RETURNs

Every RETURN item must have some way to uniquely identify it. That is, it must have a "name" of sorts. This name or identifier is specified using the AS keyword.

The AS identifier used with a RETURN item must begin with an '@'. RETURNs that are output from one analysis can be graphed or used as input to a subsequent analysis (within the same bug template). When used in another analysis, RETURNs may be referred to (within the code) as links.

Do not use the whole words @app or @tracepath as identifiers. These are keywords and have specific meanings within the code. If returning trace chains, you must use an identifier beginning with @tracepath_. Do not use @tracepath as a substring in any other identifier, as it will lead to it being processed incorrectly.

Note that there is a strict top-to-bottom processing, so any RETURN item can only be used in subsequent searches.

To illustrate, the below will work (@web_view is used after it has been RETURNed. Tool will look for the string "ABCD" within all web views that have been identified as having a call to the WebView->addJavascriptInterface method).

{
    "CODEPARAMS": {
        "SEARCH": {
            "SEARCHFORCALLTOMETHOD": {
                "METHOD": "Landroid/webkit/WebView;->addJavascriptInterface",
                "RETURN": "@method AS @web_view"
            },
            "SEARCHFORSTRING": {
                "STRING": "ABCD",
                "SEARCHLOCATION": "@method:@web_view"
            }
        }
}

But this will not (an attempt is made to use @location_abcd before it has actually been RETURNed):

{
    "CODEPARAMS": {
        "SEARCH": {
            "SEARCHFORCALLTOMETHOD": {
                "METHOD": "Landroid/webkit/WebView;->addJavascriptInterface",
                "SEARCHLOCATION": "@method:@location_abcd"
            },
            "SEARCHFORSTRING": {
                "STRING": "ABCD",
                "RETURN": "@method AS @location_abcd"
            }
        }
}

Analysis-specific RETURNs

Manifest Analysis
With RETURNs from a Manifest Analysis, if the returned value is something like an Activity name (which would correspond to a class within the app code), and if it to be used as a link for subsequent searches, then prefix the RETURN value with <smali>:. This tells the script to convert the Activity name to the equivalent smali representation.

Right now, a Manifest Analysis can only return values. It cannot use values returned by other analyses. If a use case presents itself for using a linked RETURN item as input in a Manifest Analysis, please raise an enhancement issue and we can look at adding the required functionality.

Code Trace
The RETURNs from a code trace can only have one format: <tracepath> as @tracepath_<unique_identifier>, e.g., <tracepath> as @tracepath_browsable_intent
This returns the entire trace chain as a string, with chain links separated by commas.

Code Search
This is probably the type of analysis that allows for the most flexibility with RETURNs. No special rules, apart from the restrictions mentioned in the "General Rules for RETURNs" section above.

back to top

Sample Template

Below is a valid template:

{
    "METADATA": {
        "NAME": "JSbridgeBrowsable"
    },    
    "MANIFESTPARAMS": {
        "BASEPATH": "manifest->application->activity OR manifest->application->activity-alias",
        "SEARCHPATH": {
            "intent-filter": {
                "action": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.action.VIEW"
                    }
                },
                "category": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.category.BROWSABLE"
                    }
                },
                "data": {
                    "RETURN": ["<NAMESPACE>:host AS @host", "<NAMESPACE>:scheme AS @scheme"]
                }                
            }
        },
        "RETURN": ["<smali>:<NAMESPACE>:name AS @activity_name"]
    },
    "CODEPARAMS": {
        "SEARCH": {
            "SEARCHFORCALLTOMETHOD": {
                "METHOD": "Landroid/webkit/WebView;->addJavascriptInterface",
                "RETURN": "<class> AS @web_view"
            }
        },
        "TRACE": {
            "TRACEFROM": "<method>:@web_view[]->loadUrl(Ljava/lang/String;)V",
            "TRACETO": "<class>:@activity_name",
            "TRACELENGTHMAX": 10,
            "RETURN": "<tracepath> AS @tracepath_browsablejsbridge"
        }
    },
    "GRAPH": "@tracepath_browsablejsbridge WITH <method>:<desc>:<class> AS attribute=nodename"
}
}

This might seem like a confusing mess, so let's break it down.

First, the goal of this template is to identify browsable activities that call the loadUrl method of web views that have JavaScript Interfaces defined on them.

Identifying browsable activities is something that requires a manifest analysis.

  • We specify the paths leading upto the activity level (or activity-alias) as BASEPATH because we don't care about anything at higher levels.
  • Within SEARCHPATH, we reconstruct the structure of the AndroidManifest.xml.
  • Since browsable activities are identified via intent-filters (under the category tag), we specify a LOOKFOR within the intent-filters->category key.
  • For the activity to be browsable, the name tag must have the value android.intent.category.BROWSABLE, so we specify this as a TAGVALUEMATCH requirement.
  • Note that we use a <NAMESPACE> placeholder, rather than android:name as the tag. This is because in rare cases, the namespace is not actually android. By using the <NAMESPACE> placeholder, we let Jandroid know that it should identify the namespace and replace the placeholder with the actual value.
  • We want the activity or activities that satisfy the browsable requirement to be used later, so we RETURN the name of the activity with the identifier @activity_name. Because the code analysis section doesn't work with Java-formatted class names, we specify that the activity name should be converted to smali format using the <smali> modifier.
  • Note: We specify the <NAMESPACE>:name=android.intent.action.VIEW for the action tag, but not 100% certain that it's needed...

Next, we want to identify web views that have JavaScript Interfaces defined on them, and a path between a loadUrl call on these web views and the activities returned by the manifest analysis. This is something that requires code analysis.

  • To identify web views with JavaScript Interfaces, we use a code search. We specify Landroid/webkit/WebView;->addJavascriptInterface and RETURN any class that satisfies this condition as @web_view. Jandroid will also look for subclasses that may satisfy this requirement.
  • We then tell the code to trace backwards from the @web_view classes' loadUrl(Ljava/lang/String;)V method and see if it reaches the @activity_name. We also tell the code to store the trace chain as @tracepath_browsablejsbridge. We limit the trace chain length to 10 links, to reduce trace times.

Finally, we want to graph the output.

  • We tell Jandroid to graph the trace chain, where every node should have the name formatted as method:descriptor:class.

back to top

Links

If you know that certain bugs must be exploited in a certain order, then you can specify this in a .links file. Jandroid will then create :EXPLOITS edges from one bug to another.

A valid .links file will look something like this:

{
    "BasicBrowsableIntents": ["StartActivityServiceExportedStart", "ExportedJSBridgeStart"],
    "ExportedJSBridgeEnd": ["ArbitraryDownloadsStart"]
}

Each primary key denotes the "source" template name, and each element in the list attached to the key is a bug (template) that can be exploited after the source bug. That is, "BasicBrowsableIntents": ["StartActivityServiceExportedStart", "ArbitraryDownloadsExportedStart"] indicates that you first exploit BasicBrowsableIntents and then, from that point, you can exploit StartActivityServiceExported or ArbitraryDownloadsExported.

If the bug templates that are referenced result in trace chains rather than individual nodes, then you need to specify Start and End to indicate that an exploit should begin at the End of a trace chain or go to the Start of a trace chain. That is, let's say you have 3 templates: T1, T2, T3, where T1 outputs a single node and T2/T3 output chains. Let's say the possible exploit chain is T1->T2->T3. This would be specified in the .links file as:

{
    "T1": ["T2Start"],
    "T2End": ["T3Start"]
}

If, on the other hand, the exploit chain was T2->T1->T3, the .links file would look like:

{
    "T2End": ["T1"],
    "T1": ["T3Start"]
}

Start and End are case-sensitive.

Note that, in the event that some templates are matched to a large number of APKs, the resultant graph can be slow to render and look very messy if links are also specified. In such cases, it might be better not to specify a .links file, but instead identify APKs for each bug separately.

Tips

  • If specifying traces in a template, and one trace endpoint is fully-defined (i.e., an Android method signature) and the other makes use of RETURNed/linked items, then specify the fully-defined endpoint as TRACETO and the other as TRACEFROM.