An unsafe call to sprintf that can lead to control flow redirection through a format string based buffer overflow.
Please find below a description of the vulnerability as well as a PoC.
Important notes:
The PoC assumes a users u1 with password p1 exists.
The addresses and offsets on the PoC are tuned for a fresh Kali VM. They may have to be changed depending on the machine (the following description explains how to find them).
The first parameter (placeHolder) is defined just one line above as a char buffer of size bufferSize, which is equal to 420 (see include/parsing.hpp at line 7).
The format string parameter (buffer) corresponds to the char * passed to the function bufferToString. A call to this function is made at line 62 of the file src/server/systemcmd.cpp inside command_with_output. command_with_output is used by commands that produces output, and calls bufferToString passing to it one line of the command output.
For this exploit we will consider a call to ls (which involves a call to command_with_output and thus executes the vulnerable sprintf).
Analysis
Given what above, there are a few observation we can do:
sprintf copies an arbitrary number of characters, thus we have a potential buffer overflow.
In the case of ls, the value of buffer is a directory name, which can have at most size 128.
Through mkdir we can create directories, this enable us to control the value of buffer, the format string, when a call to ls is made.
What we cannot do
A simple buffer overflow: 128 characters aren't enough to overflow a buffer of size 420.
Use the format string to do an arbitrary write overriding a return address: this will require writing much more than 420 characters to the "screen", it will overflow placeHolder by a lot and mess up the whole stack.
What we can do
Take advantage of the format string to perform a buffer overflow. In fact, thanks to %Nc we can insert N characters in placeHolder while having a directory name of only a few characters. The idea is thus to find the right offset and override the eip with the address of hijack_flow.
Exploit
Setup
Launch the server and attach gdb to it (sudo gdb -p PROCESS_ID).
Gather information
Obtain the address of hijack_flow: simply run disassemble hijack_flow in gdb.
Find out the offset of eip from the buffer. To do so we take advantage of the pattern command in gdb:
Run pattern create 25, which creates a pattern of 25 characters.
Launch a client and use mkdir to create a directory named %385c followed by the pattern.
The server segfaults because it's trying to access a non valid address, in gdb we can see that address.
If our offset guess (385) was good enough, this address should be composed by four characters of our pattern. Assume it was aaad, then running pattern search aaad will give use the exact offset.
An unsafe call to
sprintf
that can lead to control flow redirection through a format string based buffer overflow.Please find below a description of the vulnerability as well as a PoC.
Important notes:
u1
with passwordp1
exists.Where
Repository
https://github.com/LukasGelbmann/GRASS
Location
spirntf
in src/parsing.cpp at line 16Vulnerability
The call to
sprintf
sprintf
is called as follows:The first parameter (
placeHolder
) is defined just one line above as achar
buffer of sizebufferSize
, which is equal to420
(see include/parsing.hpp at line 7).The format string parameter (
buffer
) corresponds to thechar *
passed to the functionbufferToString
. A call to this function is made at line 62 of the filesrc/server/systemcmd.cpp
insidecommand_with_output
.command_with_output
is used by commands that produces output, and callsbufferToString
passing to it one line of the command output.For this exploit we will consider a call to
ls
(which involves a call tocommand_with_output
and thus executes the vulnerablesprintf
).Analysis
Given what above, there are a few observation we can do:
sprintf
copies an arbitrary number of characters, thus we have a potential buffer overflow.ls
, the value ofbuffer
is a directory name, which can have at most size128
.mkdir
we can create directories, this enable us to control the value ofbuffer
, the format string, when a call tols
is made.What we cannot do
A simple buffer overflow:
128
characters aren't enough to overflow a buffer of size420
.Use the format string to do an arbitrary write overriding a return address: this will require writing much more than 420 characters to the "screen", it will overflow
placeHolder
by a lot and mess up the whole stack.What we can do
Take advantage of the format string to perform a buffer overflow. In fact, thanks to
%Nc
we can insertN
characters inplaceHolder
while having a directory name of only a few characters. The idea is thus to find the right offset and override theeip
with the address ofhijack_flow
.Exploit
Setup
Launch the server and attach gdb to it (
sudo gdb -p PROCESS_ID
).Gather information
Obtain the address of
hijack_flow
: simply rundisassemble hijack_flow
in gdb.Find out the offset of
eip
from the buffer. To do so we take advantage of the pattern command in gdb:pattern create 25
, which creates a pattern of 25 characters.mkdir
to create a directory named%385c
followed by the pattern.aaad
, then runningpattern search aaad
will give use the exact offset.Exploiting the Vulnerability (PoC)