Overthewire Vortex Level10

This level is mainly about code analysis and reversing. I’ve used radare2 for creating a graph from the binary, to help the reversing process.

I’ve ended up, with the following pseudo-code:

vmagic = times(&tms)
vmagic += (tms.utime + tms.stime + tms.cutime + tms.cstime)
vmagic += clock();
tmagic = time(NULL);
vmagic += tmagic;

vmagic = 0x80 - (vmagic - (vmagic>>8)<<8);
srand(tmagic + vmagic)
int setvbuf(stdout, NULL, 2, 0);
for(int i=0; i< vmagic; i++) {
for(int ebx=0; ebx < 20; ebx++) {
    buffer[ebx] = rand();
    printf(" %08x,", buffer[ebx]);

read(0, void -0x70(%ebp), 4);
if(-0x70(%ebp) == -0x6c(%ebp)) {
    setresuid(geteuid(), geteuid(), geteuid());
    execlp("/bin/sh", "sh", "-i", NULL);
} else {
    printf("Nope, try again");

After checking the code, vmagic can take values from the domain (-128…128), independent from the values generated by the functions that take part in generation of vmagic.

I’ve created a wrapper which leaks the value of tmagic,

int main() {
    char buffer[1024];
    int magic =  time(NULL);
    printf("Magic: %x\n",magic);

and a small utility which takes the value of tmagic and the first value of the random sequence, and tries to find a match: (I’m only using the first value from the sequence to check the matching, because it is very impossible, that the same value is occurring in a differently “seeded” sequence.)

int main(int argc, char **argv) {
    int seed, match, i,j;
    scanf("%x %x" ,&seed,&match);
    for(i=-256; i< 256; i++) {
        for(j=0; j<256; j++) {
            int r = rand();
            if(r == match) {
                int xx = seed+i;
                printf("%c%c%c%c\n", xx&0xff, (xx>>8)&0xff,(xx>>16)&0xff,(xx>>24)&0xff);

The only thing left is to start the utility with its output stream piped int the binary input stream, and copy the values from the binary’s standard output to the input of the utility:

./l10t | ./l10w
Magic: 4d04793e
[ 6df09f8c, 589e950d, ... ]
4d04793e 6df09f8c.
sh-3.2$ sh-3.2$ exit

We popped a shell but it quits immediately. Remember, the same problem occured on level1. Lets try the same solution we used back then. I’ve added the following lines to the utility:

    for(i=0; i<4096; i++) {
    printf("cat /etc/vortex_pass/vortex11\n");

Now lets try again:

./l10t | ./l10w
Magic: 4d0479dc
[ 27811555, 02c303d6 ... ]
4d0479dc 27811555.
sh-3.2$ sh-3.2$ sh: AAAAA[...]AAAAA
sh-3.2$ uid=514(vortex11) gid=513(vortex10) groups=513(vortex10)
sh-3.2$ *********
sh-3.2$ exit

Was easy, huh? 🙂

This entry was posted in Wargame and tagged , , . Bookmark the permalink.

8 Responses to Overthewire Vortex Level10

  1. Pingback: Overthewire Vortex Level11 | Axtaxt's Blog

  2. Jake says:

    You missed something minor but significant: as you can see from your pseudocode, the level10 binary will throw out the first vmagic rand() calls before it then outputs 20 rand() calls, but only if vmagic is positive. If vmagic is negative, it doesn’t throw anything out.

    So you code works only half the time, when vmagic is negative or zero. Anyway, I just did this level in under an hour via a very sloppy trick: I just assumed vmagic == 0 (true with probability 1/256) and did
    $ while : ; do ./soln10 | /vortex/level10; done 2>&1 | grep -A2 sh
    where ./soln10 just outputs time() in binary followed by “cat /etc/vortex_pass/vortex11”

    It takes an expected 256 tries before it works, but it took me like 5mins to write the C program and this one-line script and … voila!

    • axtaxt says:

      I’ve checked it again, and my solution worked 12 times out of 12 probes. If you check the code again, I run the search for the random number in a very big domain: 512 starting seeds and 256 items long random sequences. It could be narrowed but I was lazy :-).

      Btw: I like your solution :-)!

      • Jake says:

        Ah yes, I see. I didn’t notice you were trying all seed offsets AND looking down the rand() list. So I will revise my statement: half of the time your exploit works for j == 0 (because i will be <= 0 whence the first rand() call will match) and half of the time you will have to iterate j up to a maximum of 128.

        In any case, your solution does indeed work 100% of the time and you certainly have plenty of time to do it this way. My apologies for saying otherwise.

        These annoyances with "bash -i" are silly. I wish there were an easier solution than these ugly hacks you and I have used. With level 1, setting terminal options correctly lets you cut & paste the \xca byte, then the -i shell doesn't hurt you. But here, to properly handle things, you'd have to write a wrapper that forks level10 as a child, reads from its file descriptors to get the rand() outputs, then find the seed, send that back to the child stdin descriptor, wait for a shell, then hand control back to the user. What a pain!

        If "expect" were installed on vortex it would make things so much easier. I guess we could install such software since scp works, but I'm too lazy to go build statically linked binaries on a 2.4 kernel and then transfer them.

  3. axtaxt says:

    Do you know what could be the author’s original idea to overcome the “-i” mode? I’ve only accidentally found this “hack” I use currently. Can you show me what kind of terminal options do you use on level 1?

    I had not known expect before. Thanks, it can be helpful in a lot of cases.

  4. greg says:

    An alternative to “expect” would be “empty”!


  5. axtaxt says:

    There is a stackoverflow topic about the problem of the “AAAAAA”-s. Check it if you are interested.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s