Hackthebox – Ellingson – why the right libc version matters

During the Hackthebox Machine called Ellingson, one of the requirements was to create a Buffer Overflow using Return Oriented Programming and the libc library to call a the system() function and a /bin/sh shell. With this, I got stuck for a while because I did not know that I had to use the libc libary from the target machine instead of my own libc. After someone told me that it was a mistake to use the local libc, I fixed it using the remote libc but was none the wiser as of why this would not work.

The only thing I could do was analyze the libraries to determine the differences and understand what was going on. Since the libc file is called libc.so.6 on both systems, I decided to copy it to a local directory on my kali box and name the local file libc-local. The remote-file, for obvious reasons, was called libc-ellingson.

One of the things that you have to do when creating the buffer overflow, is locating the exact memory offset where the required command is called. This can be done using pwntools as I describe in both the Hackthebox – Safe and Hackthebox – Ellingson write-ups. It can however, also be done using Linux command line tools such as readelf and strings. Below it becomes obvious why using the local libc file does not work, if you call it on a remote system where the called binary actually uses the local (in this case ellingson) libc library.

First we find the memory offset for puts

root@kalivm:~/test# readelf -s libc-local |grep " puts@@GLI"
   426: 0000000000071910   413 FUNC    WEAK   DEFAULT   13 puts@@GLIBC_2.2.5
root@kalivm:~/test# readelf -s libc-ellingson |grep " puts@@GLI"
   422: 00000000000809c0   512 FUNC    WEAK   DEFAULT   13 puts@@GLIBC_2.2.5

Here we can see that on my local kali box, the memory location would be 71910, while on the target system it would be 809c0. Let’s do the same thing for the system() call.

root@kalivm:~/test# readelf -s libc-local |grep " system@@"
  1418: 00000000000449c0    45 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.2.5
root@kalivm:~/test# readelf -s libc-ellingson |grep " system@@"
  1403: 000000000004f440    45 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.2.5

Here, yet again, we see differences. On the kali box, the location is 449c0 while on the target it would be 4f440. The last one, the ‘/bin/sh’ call can not be found using readelf, instead we use strings to find the exact location.

root@kalivm:~/test# strings -a -t x libc-local |grep bin/sh
 181519 /bin/sh
root@kalivm:~/test# strings -a -t x libc-ellingson |grep bin/sh
 1b3e9a /bin/sh

Although the output is slightly different, we see yet again that the kali location is 181519 while the location in the target libc file is 1b3e9a. This shows clearly to me why, when writing an exploit, one should always use the target libc if that is available. Or, as someone put it to me, identify the target system and make sure to get the corresponding libc from somewhere if you do not have direct access to it!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.