Challenge 10 is another nostalgic one for me. Back when I was first starting with linux, I remember reading about overflows and race conditions. This challenge is the latter, a race condition.
We’re given a C/C++ app to exploit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
The problem with this code, is that it first checks to see if the user running the problem has access to the file (on line 24). It then assumes for the rest of the execution of the program, that we still have access to it. The point of this exercise is to trick the program by switching out the file while the program is running. Hence a race condition.
On the BackTrack machine (10.1.1.132 for me), I ran 2 terminals. The first contained:
The second contained:
I ran both of these so that the first one would continuously open up a listening socket connection on port 18211 (per the vulnerable program), and append all information received to “out.txt”. The second command would continuously watch out.txt and output any lines that didn’t have the little banner the vulnerable program uses. That way I didn’t get spammed with trash I didn’t care about.
Now on the Nebula machine, I ran 2 more terminals. In the first, I ran:
And the second:
These commands are pretty simple to pick apart. They both are endless loops, just like the earlier NetCat session. The first would create a symbolic link to /tmp/token10. However, it would alternate between using /tmp/token (a blank file I made), and /home/flag10/token. The idea is to try using /tmp/token when the access() is called in the vulnerable program, but then have /home/flag10/token be there when we actually send the file. It’s unreliable, but will eventually work. The second command runs the vulnerable program, passing it the symlinked file and the BackTrack IP. I used nice, to lower the priority as low as possible, so that hopefully the symlinking loop would operate faster.
When you have all of these terminals running, it’s just a matter of time before you get the token sent to you. Some iterations of flag10 will fail, some will succeed. Just watch the second terminal on the BackTrack machine, and eventually you’ll see the token come over. You should see this flying across the screen:
Just stop all the terminals, and you should be done with this challenge. I did learn quite a bit on this one, as it was honestly my first race condition I’d ever had to exploit. My original methodology was to use GDB to start the program, and set a breakpoint after the initial access() was done. Then switch the file manually, and resume. This worked brilliantly, however I learned that when dealing with SUID programs, you can’t use GDB on them, unless you run GDB as root. This is a security design of Linux. So instead, I had to go with the quirky commands. I’m still interested in seeing if it could be done with a custom C++ app which would invoke flag10, and attach to the process using ptrace to duplicate my GDB idea. I just don’t know if it’ll work or not.