Skip to content

Stock Triggers

Paul Marinescu edited this page May 28, 2014 · 1 revision

Stock Triggers

LFI comes with a set of useful triggers which you can use out-of-the box for your injection experiments and as a starting point for creating new triggers:

Random trigger

Description

The Random injection trigger (class RandomTrigger) can be used to inject with a configurable probability in each associated function call.

Example

To create a trigger instance that injects with 40% probability use the following XML snippet in your scenario

<trigger id="random40" class="RandomTrigger">
  <args>
    <percent>40</percent>
  </args>
</trigger>

Call stack trigger

Description

The Call stack injection trigger (class CallstackTrigger) can be used to inject when the current call stack matches a predefined (partial) call stack. More exactly, the trigger tries to match the outermost frames of the current call stack (excluding the frames belonging to FIT) with the given call stack.

Each given frame can be specified to match

  • Any part of an executable module
  • Any part of an executable module and a file name (if debug information is available)
  • Any part of an executable module, file name and line number (if debug information is available)
  • The absolute offset of a function call

Usage

  • When using a frame that matches any part of an executable module use either:
    • __main - to specify that the main executable is targeted (no libraries)
    • library name including extension
  • When using a frame to target a module, file name (with or without line number), always use the full module path. The file name will be matched against the last part of the file name from the debug information i.e. the path is optional
  • When using an absolute offset (usually after disassembling the program), give the offset in hexadecimal form (e.g., 0x8049cf0)

Example

The trigger below injects in calls made by the mysqld module, file mi_create.c, through a wrapper that can be anywhere in the mysqld module.

<trigger id="t" class="CallStackTrigger">
  <args>
    <frame>
  	  <module>__main</module>
    </frame>
    <frame>
      <module>/home/paul/mysql-5.1.44/sql/mysqld</module>
      <file>mi_create.c</file>
      <!-- <line>832</line> -->
    </frame>
  </args>
</trigger>

Caveats

  • Injecting in libraries, by specifying only the library module can give unexpected results. This happens because the trigger does not determine the library size in memory; a default size of 512KB is used.
  • Injecting in the main executable, by specifying only the module (i.e., __main) can give unexpected results when the injection library is loaded in multiple processes (as in the case of a test suite) because faults may be injected in other processes. Use the form __main_''entry_point'' (e.g., __main_0x8049cf0) to specify that injection should happen only in an executable with the given entry point. The entry point can be determined via readelf -h /path/to/program

Call count trigger

Description

Used to inject after a specific number of invocations.

Example

Trigger instance that injects after being invoked 40 and 55 times.

<trigger id="cc" class="CallCountTrigger">
  <args>
    <callcount>40</callcount>
    <callcount>55</callcount>
  </args>
</trigger>

Program state trigger

Description

The state trigger allows injection when a predicate based on program variable holds. The implementation supports global and local variables of integer and string (char*) type and the equality predicate.

Usage

Specifying variables is done differently for global and local storage. For global variables, the absolute offset of the variable must be provided. This can be obtained via gdb using the ''info address '' command after loading the target executable, assuming debug symbols exist. For local variables, the stack frame where the variable resides, relative to the frame that makes the library call, must be provided along with the variable offset (ebp-relative) inside the frame. A [DetermineLocalVariables detailed walkthrough] is available.

Example

Specifying a local variable:

<trigger id="l1" class="StateTrigger">
  <args>
    <local>
      <frame>24</frame>
      <offset>-0x8</offset>
      <type>string</type>
      <value>foo</value>
    </local>
  </args>
</trigger>

Specifying a global variable:

<trigger id="g1" class="StateTrigger">
  <args>
    <global>
      <offset>0x8049cf0</offset>
  <type>int</type>
  <value>2010</value>
    </global>
  </args>
</trigger>

Caveats

If the targeted function is called from multiple places (or with different call stacks), evaluating local variables may result in undefined behavior. It is good practice to accompany any local variable evaluation with a call stack trigger that only matches the particular call stack of interest.

Single injection trigger

Description

Each instance of the single injection trigger evaluates to true the first time its Eval function is called and to false otherwise. The trigger does not take any arguments. It is useful in combination with other triggers, usually as the last-to-be-evaluated.

Example

<trigger id="single" class="SingleTrigger" />
<trigger id="l1" class="StateTrigger">
  <args>
    <local>
      <frame>24</frame>
      <offset>-0x8</offset>
      <type>string</type>
      <value>foo</value>
    </local>
  </args>
</trigger>

<function name="opendir" retval="NULL" errno="EMFILE">
  <triggerx ref="l1" />
  <triggerx ref="single" />
</function>

DTD reference for the most common stock triggers

+----------------------------+------------------+--------------------------------------+
|Trigger Purpose             |  Trigger Class   |  Arguments                           |
+----------------------------+------------------+--------------------------------------+
|  Random injection trigger  |  RandomTrigger   | <!DOCTYPE args [                     |
|                            |                  |  <!ELEMENT args (percent)>           |
|                            |                  |  <!ELEMENT percent(#PCDATA)>         |
|                            |                  | ]>                                   |
+----------------------------+------------------+--------------------------------------+
|Call count trigger - inject | CallCountTrigger | <!DOCTYPE args [                     |
|the fault when the function |                  |  <!ELEMENT args(callcount+)>         |
|is called a specific number |                  |  <!ELEMENT callcount (#PCDATA)>      |
|of times                    |                  | ]>                                   |
+----------------------------+------------------+--------------------------------------+
|Callstack trigger - inject  | CallStackTrigger | <!DOCTYPE args [                     |
|when the current call stack |                  |  <!ELEMENT args(frame+)>             |
|(partially) matches a given |                  |  <!ELEMENT frame(module,file?,line?)>|
|call stack                  |                  |  <!ELEMENT module (#PCDATA)>         |
|                            |                  |  <!ELEMENT file(#PCDATA)>            |
|                            |                  |  <!ELEMENT line (#PCDATA)>           |
|                            |                  | ]>                                   |
+----------------------------+------------------+--------------------------------------+