tl;dr
- Heap Overflow in glob function while handling
Tilde
operator. - Abuse null byte overflow to gain RCE.
Challenge Points: 983
No of Solves: 9
Challenge Author: Cyb0rG
Challenge Description
A Super secure path finder from your own 2017.
To start with , the challenge handout folder contains the binary , chall.c
and glob.c
.
The binary is a standard CTF-style executable. According to the description , the challenge is running on standard ubuntu 20.04
docker container so the libc naturally is 2.31
.
Initial Analysis
There are 4 straightforward functions
- Add Path - Takes a pattern of user supplied size (limited to 0x1000) , mallocs it and stores it in a global array of patterns.
- Check Path - Takes an index , and uses the
glob
function to check if there exists a pathname matching the pattern. - View Path - Takes an index and prints the pattern.
- Remove Path - Frees the memory containing the pattern at a user specified index , and nulls out the global array.
It is fairly trivial to get a libc leak , since malloc is used and size limit is 0x1000 , we can easily leak a libc main arena pointer to start with.
But where is the actual exploitable bug? The answer partly lies in the description as well as the glob.c
provided. A quick internet search on glob cve 2017
quickly reveals the presence of an overflow while mishandling the Tilde
operator. A little more research reveals a public poc available too.
Using the poc , we can see that we immediately trigger crash with malloc() corrupted top chunk
.
Analysis of CVE-2017-15804
The code path which triggers the heap overflow is as follows -
In glob.c line: 523
, the first call to malloc happens and the data string is stored on heap.
1 | else |
We are interested in the part of code from line: 575 of glob.c
1 | if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') |
- The very first character should be
~
and the flags should have the GLOB_TILDE to get into the if condition.
Now , from line: 709 of glob.c
, we see -
1 | char *end_name = strchr (dirname, '/'); |
- Input must contain a
/
so that theend_name
is not null and we reach the else condition whereunescape
is initialized. - Input should also contain
\\
as unescape should not be null for triggering the heap overflow.
If all this is well , another malloc is called to store the string of size end_name - dir_name
.
We have a lot of variables on out plate , so let’s just list them all together at once.
- newp = malloc(endname - dirname)
- dirname = input pointer
- endname = address of first occurence of
/
- unescape = address of first occurence of
\\
The following if
condition is the actual cause of heap overflow.
1 | if (unescape != NULL) |
- The call to
mempcpy
copies into thenewp
pointer , input of sizeunescape - dirname - 1
. - In a while loop , it is checked if the unescape string is
\\
, if not , the character atunescape
is copied into the region after mempcpy.
Observation : It keeps copying the entire string without any out of bounds check and thus causes the heap overflow.
Exploit Idea
Using the public poc , we can check in gdb how things look and do some basic crash analysis.
In one iteration
1 | 0x55555555b390: 0x0000000000000000 0x0000000000000061 |
In next iteration
1 | 0x55555555b390: 0x0000000000000000 0x0000000000000061 |
This is what causes the malloc() corrupted top
.
For the sake of ease of debugging , I have provided the challenge binary with debug symbols and source code stepping within gdb.
Null byte to the rescue
After playing around with the poc and tweaking it a bit , we realize that overflow is happening only with 0x2f
byte which really isnt very interesting in terms of overwriting a tcache pointer fd or unsorted bin since it’s not aligned. But with some effort and tweaking the poc , we can actually get a null byte overflow which is very powerful primitive as we all know.
With the null byte overflow , we can easily point tcache fd of a chunk to point to a fake chunk which resides at the memory ending with \x00
. With this , we can successfully construct a fake chunk containing free_hook
as fd.
Conclusion
I had randomly come across this CVE and found it very interesting, I hope you enjoyed solving the challenge.
Here is the complete exploit.
Flag - inctf{CVE-2017-15804_Subtl3_H3ap_Overfl0w}