-
Notifications
You must be signed in to change notification settings - Fork 9
Usage
The tracer.simple can trace small binary payloads. Below is an explanation of the main functionality.
git clone https://github.com/teodor-stoenescu/river.sdk.git
# follow readme instructions
git clone https://github.com/teodor-stoenescu/simpletracer.git
git submodule init
git submodule update --remote --recursive
# clone https://github.com/Z3Prover/z3.git and follow the instructions
export Z3_ROOT_PATH=<z3 install path>
mkdir build; cd build
cmake -DCMAKE_INSTALL_PREFIX=. ..
make
python -c "print 'A' * 100" | ./bin/river.tracer -p <target file>
The tracing mode can be either inprocess or extern. Inprocess tracing involves loading a shared object as payload while extern execution involves creating a separate process.
Specify inprocess tracing with the --inprocess
command line option. Extern tracing is not supported at this time, but will be specified with the --extern
option. Obviously, these options are mutually exclusive.
The execution trace is written to a file. You can specify the file using the -o|--outfile
command line option. If left unspecified the trace is written to the trace.simple.out
file.
The payload needs to be specified in the form of a shared object (.so/ELF on linux, .dll/PE on Windows). You can control the payload using the -p|--payload
command line argument.
The tracer supports complex tracing methods like tainted index
and z3
.
Specify --annotated
to obtain traces with taint propagation. Taint propagation traces layout is explained below.
Taint propagation refers to tracking how input data is used along program execution. Using this technique we can discover if program flow or memory read/write actions can be controlled by input.
Taint propagation technique starts with the assumption that all input bytes are tainted. We refer to input bytes as p[i], where i is a valid index in the input stream.
Taint propagation data layout refers to five different situations:
- Initial input propagation
I[k] <= p[i]
, where I[k] represents the tainted index, p[i] represents ith input byte and the assignment represents taint propagation of input byte i.
Taint propagation needs means to cut data or to concatenate data. Consider you have an unsigned integer that is tainted and you want to continue processing only its first byte. The corresponding x86 instruction would be mov al, BYTE PTR[ebp + 8]
. We refer to this operation as extract operation. We also need to support the operation in which data is concatenated together, for example two words are placed in a double word. We refer to this as concat operation. Thus, we have:
-
Extract propagation
I[k] <= I[index][offset:size]
, where I[k] represents the tainted index, I[index] represents the tainted index that needs the extract operation, offset is the offset inside I[index] where we start the cut and size is the number of bytes we want to cut starting with offset. All these operations are referred in little endian layout. Considering you need to cut first byte of a double word stored in memory, the associated extract propagation is:I[k] <= I[index][0:8]
. -
Concat propagation
I[k] <= I[p] ++ I[q]
, where I[k] is the tainted index, I[p] is first concatenation operator and I[q] second operator. One x86 instruction that generates this taint propagation is:mov eax, 0
mov al, byte[ebp + 8]
Concatenation happens between three bytes of 0x00 (most significant) and one byte representing the actual tainted data from input (least significant byte). -
Const value used in tainted index propagation
I[k] <= const <constant value>
, where I[k] is the tainted index that refers to the const value. This is a system artifice used to allow extraction and concatenation of data with arbitrary constant values. -
Execute taint propagation
I[k] <= <flagname>:I[q] | I[p]
, where I[k] is the tainted index,<flagname>
:I[q] represents the tainted flag along tainted index corresponding to flag. I[p] represents the tainted index corresponding to a generic tainted operand.