Part 33 Buffer Overflow
Taint Analysis on Binary
In Assembly, how do we know where the data goes
We want to run Taint Analysis on binary
Here, there is no more mention of variable names like input and buffer
We have to work with registers and memory addresses
Finding the Source
First, we need to find out where the data entered the program from, for example, in a Linux program, we might get this
call read
or
call recv
Suppose we have this before
lea rsi,[rbp-40h]
mov edx,40h
call read
Here we can have a simple path
External Input
↓
read()
↓
[rbp-40h]
So the input data is placed in [rbp-40h]
This point can be our Source
Following the data
Now we see a few commands below
mov rax,[rbp-40h]
mov rcx,rax
So the value came from memory Inside RAX
Then entered RCX
The current path is
[rbp-40h]
↓
RAX
↓
RCX
Following data transfer
Suppose we see this later
mov rdx,rcx
call process_data
Now
[rbp-40h]
↓
RAX
↓
RCX
↓
RDX
↓
process_data()
That is, the data that came from outside entered process_data
Now we have to continue the path inside that function
Reaching Sink
Suppose we reach this inside the function
mov [rdi],rax
Here we have a Memory Write
So our general path becomes
Input
↓
read()
↓
Stack / Memory
↓
Register
↓
Function
↓
Memory Write
This point can be our desired Sink
Of course, reaching a Write alone does not mean there is a vulnerability
The size and access range should also be checked
Taint
Registers
Assuming
mov rax,[rbp-40h]
and [rbp-40h] contains external data
so
RAX = Tainted
then
mov rcx,rax
now
RCX = Tainted
then
add rcx,8
The RCX value has changed but is still dependent on the original data
so the Taint path is not broken
but one important point
not all instructions cause a simple Taint transfer
for example:
cmp rax,10h
here the data is not directly transferred to another register
but the RAX value affects the program's decision
for example:
cmp rax,10h
ja invalid
so here we have a Control Dependency, that is, the external data affects the program's execution path
A more complete example:
lea rsi,[rbp-40h]
mov edx,40h
call read
movzx eax,byte ptr [rbp-40h]
cmp eax,20h
ja invalid
mov edi,eax
call process_data
See the path step by step
read()
↓
[rbp-40h]
↓
EAX
↓
cmp
↓
Control Flow
↓
process_data()
Here the input value affects both the data and the execution path
What do we do in Ghidra
When we reach a suspicious value
First we check the References of that value, then we find the next uses
For example:
Source
↓
Reference
↓
Register
↓
Memory Access
↓
Function Call
Then we continue the same for the next function to determine the full path. One important point is that you don't always have to do the entire Taint Analysis manually
In large programs, this can be very difficult, so there are various tools that can automate this task to some extent
For example:
angr
Triton
DynamoRIO
Intel Pin
Each has its own method and application
@reverseengine