Here are my solutions for the ringzer0 Jail Escaping C challenges:
- Level 1: https://ringzer0team.com/challenges/228
- Level 2: https://ringzer0team.com/challenges/229
- Level 3: https://ringzer0team.com/challenges/230
Level 1
|
|
So obviously I have to write some C code to read the content of /home/level1/flag.txt
. fopen
/fread
are not allowed so let’s do it using open
/read
:
|
|
Keep in mind that you’ll have to paste only the contents of main()
:
|
|
Level 2
|
|
Pretty much the same as in the first challenge. However, some functions like fopen
, open
, fdopen
were not allowed. Finally I bought the hint:
Is there a 64 bits wrapper for open?
And of course there is open64()
. open()
and open64()
use the open
syscall internally. The main difference is that open64()
is equivalent
to open()
with O_LARGEFILE in order to support large files in 32 bit applications. Here is my solution (shitty code, don’t use in production :D):
|
|
Level 3
|
|
I must admit that although this challenge wasn’t that difficult it took me way to much time to find a reasonable solution. My first ideea
was to write shellcode
that would read flag.txt
and dump its content. This is also the reason I wrote “Testing Shellcodes”. However, I’ve noticed that \x
(hex code) couldn’t be used as a keyword. Instead of giving up my
first idea I should have think of some way how to re-write those hex codes to sth different: octal values or integer values of chars. That way I would have had bypassed the \x
restriction.
First I’ll try to write down my thoughts which lead to the solution. Afterwards I’ll show some other cool solutions I’ve seen in the write-ups.
My solution
After trying hard I’ve decided to buy the hint:
|
|
Then I was looking for another preprocessor directives meant to embed/include code in other files. But I didn’t find sth useful. Besides that all preprocessor directives start with ‘#’ which was a bad keyword. However, this assumption was wrong.
Somebody told me then that I should look for an “old function” which could do the same. Functions, you say. All’right! At (https://www.gnu.org/software/libc/manual/html_node/Function-Index.html)[https://www.gnu.org/software/libc/manual/html_node/Function-Index.html] you can find all libc functions available. But I had to do some filtering:
- since the open and read keywords weren’t allowed, I wasn’t able to create any file streams (FILE *) or file descriptors (int fd)
- that means that all functions taking a
FILE *
pointer or a file descriptorint fd
weren’t suitable
- that means that all functions taking a
- the
exec*
family (execl, execlp, execle, execv, execvp, execvpe) was also not a good ideea since these functions were disabled by theLD_PRELOAD
override malloc
was also disabled by the override so no functions using malloc internally could be used
Finally I was desperately searching for some functions but I couldn’t find one. I think I was overthinking the solution way to much: I
was hoping to find a function (in the context of C code) which would then include flag.txt
and try to interpret its content as valid
C code. Since the flag file contains no valid code, the compiler will then produce some error messages which hopefully will dump the flag
inside flag.txt
. Unfortunately after “parsing” the libc functions index site I couldn’t find anything.
Finally, somebody (thx nsr @nullsecurity.net IRC channel) told that there might be a way to accomplish “#include” without using “#”. The hint I was after was called Digraphs/Trigraphs. Especially for the C language the preprocessor is able to replace digraphs/trigraphs by their single-character equivalents before any other processing. This way I was able to trigger the error message I was hoping for:
|
|
There we go: FLAG-BE79t326XS03122r5A4206tv395P64WB
Other solutions
Bypass LD_PRELOAD
As I’ve noticed some functions (among these also execve()
) were disabled due to the LD_PRELOAD
override. Some smart guy managed it to find in memory the real libc functions and thus bypassing the LD_PRELOAD
override. Using libcdb.com you can identify the exact version of the used libc version by finding out the addresses of some functions (in his case puts
and printf
):
|
|
After finding the exact libc version, he/she downloaded the file and had a look at it:
|
|
By calculating the offset between puts
and execve
he/she could then build following code:
|
|
Clever!
Execute shellcode
Since I was initially trying to execute shellcode, I was very curios about any similar solutions. killer2 had a very elegant solution:
|
|
Nice!
You can find here more information about function attributes.