Solving overthewire 0-11

This is going to be a long post or series of posts. I will be solving and documenting each solution of Vortex game at OvertheWire for fun [^.^]/

Level0

Your goal is to connect to port 5842 on vortex.labs.overthewire.org and read in 4 unsigned integers in host byte order. Add these integers together and send back the results to get a username and password for vortex1. This information can be used to log in using SSH.
Note: vortex is on an 32bit x86 machine (meaning, a little endian architecture)

When we connect we get

So we have to connect to it, get these 4 numbers add them togeather and send it back.

and.

next...

Level1

We are looking for a specific value in ptr. You may need to consider how bash handles EOF..

so what we have here ? buf an array of 512 bytes. ptr is buf+(512/2) so it's pointing to the middle of buf. Meaning ptr+256 is the end of buf which is buf+512, and ptr-256 is equals to buf ptr-256-4 is ptr itself :>. The way these variables are layed out in memory are (in order) ptr, x, and buf.

from IDA the main stack looks something like

so since ptr is at &buf[256] we need to decrement it by 256 then by 4 so it reaches itself and let it have 0xca...... so when this value is and'ed it will results in 0xca00000000

next

Level2

Create a special tar file

this takes argv[1-3] as files to be added to /tmp/ownership.$$.tar note here that "$$" is a special shell character that converts to the process pid you have to not use the special character by adding the backslash to not make it evaluate to the process pid.

next

Level3

This level is pretty straight forward. Just sit down and understand what the code is doing. Your shellcode will require a setuid(LEVEL4_UID) since bash drops effective privileges. You could alternatively write a quick setuid(geteuid()) wrapper around bash.
NOTE: ctors/dtors might no longer be writable, although this level is compiled with -Wl,-z,norelro.

so we need to make lpp to be an address in 0x0804XXXX since otherwise it will catch this and exit before it does what we want. Next we want it to contain something that can be dereferenced, so what's something in 0x0804XXXX that can be useful and will let us control eip ? It's exit@got.plt :)

let us see how that last exit in main is called.

follow it it'll take you to

so if we use 0x08048320+2 we'll have something in 0x0804XXXX pointing to 0x08049738 which is exit@got.plt. so if *llp=0x08048320 then **llp=&buf will set the exit@got.plt to &buf meaning that when call exit happens it will jmp to buf[0]... and

Level4

This is the common format string bug, exploit it with care though as a check is made with argc. What is the layout of a process’s memory? How are programs executed?

This is a format string vulnerability. It has a small trick at the beginning it says that if you input any arguments then you fail! but you have to enter argv[3] so how is that possible ?

looking at the main stack looks something like

So if we execute the binary passing it argv = {NULL} then it'll use envp instead :), so let us write a wrapper around it.

this runs the level passing it {NULL} arguments thus argc == 0 and it won't exit, and we reach envp where it will use envp instead. now we just pass format string stuff to it. Our plan is to overwrite exit@got.plt so we need it's address.

we need to write on 0x0804a008 and 0x0804a008+2 our address in two parts. First part will contain the first part of our address, and the second part will contain the second part of our address. We first need to find offsets to a controlable place so we can put these two addresses there, and write on them our address.

so we find that our AAAA's at offset 134 and our BBBB's at offset 200 we set those to the exit got address. Then we set A to exit@got.plt and B to exit@got.plt+2 then we write A with 0xffff and B with 0x0ee0 for example or whatever we have our data. Then we add a huge payload since size doesn't matter.

we write using $hn holder. For eg: want to write 0x1111 at B then 0x1111-length(whatever we have already written). Then if we want to write 0xeeee at A then 0xeeee-"whatever in the second part" here is approximatly is B's value. To calculate them accureatly and faster just look at the debugger and get the exact values if you have made a mistake in B or A. Here we will use %03296x%134$hn which says write 03296 bytes at 134 which is A, and write %00000061727x%200$hn 61727 bytes at 200 which is B. I added those trailing zeros to help me align the stack so I get the right A, and B, because any changes in the stack will mostyl affect the alignment

next..

Level5

A password is required for the next level. vortex5.c and md5.h. a-z,A-Z,0-9 is the search space. The password length is 5 chars long, it was originally 7 chars long.
Collision(s) tested : 489265082 in 217 second(s), 361 millisec, 101 microsec.
Average of 2250932.1 hashes/sec.

This one is pretty simple just bruteforce the hash above 155fb95d04287b757c996d77b5ea51f7 result is rlTf6

Level6

We are provided with a binary file Vortex6[1]. We open it and get.

1: http://overthewire.org/wargames/vortex/vortex6.bin

Translating this to C will be

so if we have envp then restart(). which looks like

we control argv[0] so we can execute any command. We need to have envp and set argv[0] to the file we want to run.

next

Level 7

This level requires CRC_32(argv[1], strlen(argv[1])) to be 0xe1ca95ee. You might need to extract the crc tables from the program.

I hoped for this not to be an actual crc32 because I don't like reversing crypto, but it was.So first we dump the crc32 table from the binary it's a 256 bytes array it contains the table used to do the crc calculation at the binary it's at 0x080485E0 we reverse the crc32 algorithim which has the following assembly

in c it looks something like

we make sure it gives us same values as in the binary. Now I have spent some time reading on reversing crc32 as I haven't dealt with this before and it's not that complicated. What we need is "kindof" derive the actual values of the current crc32 then we calculate a new crc32 and create a value that if appended in the bytestream it will make the crc32 equals what we wanted. Thus we can inject extra data in the bytestream and adding our pad that will cause the crc to be the same. If we do that we reach the strcpy function in main and we can overflow buf, ...etc So how we do this ? instead of rephrasing what others said I'll just quote anarchriz[2] post about the subject.

2: http://www.woodmann.com/fravia/crctut1.htm

Take for CRC register before, a3 a2 a1 a0 -> AB CD EF 66
Take for CRC register after, f3 f2 f1 f0 -> 56 33 14 78 (wanted value)
Here we go:
First byte of entries entry value
e3=f3 =56 -> 35h=(4) 56B3C423 for e3 e2 e1 e0
d3=f2+e2 =33+B3 =E6 -> 4Fh=(3) E6635C01 for d3 d2 d1 d0
c3=f1+e1+d2 =14+C4+63 =B3 -> F8h=(2) B3667A2E for c3 c2 c1 c0
b3=f0+e0+d1+c2=78+23+5C+66=61 -> DEh=(1) 616BFFD3 for b3 b2 b1 b0
Now we have all needed values, then
X=(1)+ a0= DE+66=B8
Y=(2)+ b0+a1= F8+D3+EF=C4
Z=(3)+ c0+b1+a2= 4F+2E+FF+CD=53
W=(4)+d0+c1+b2+a3=35+01+7A+6B+AB=8E
(final computation)
Conclusion: to change the CRC-32 register from ABCDEF66 to 56331478 we need
this sequence of bytes: B8 C4 53 8E

let us continue, we write the code that does all this, which is

then we overwrite eip and find where our shellcode is at...

next..

Level8

Disassemble this dynamically linked executable.

A binary file is provided here[3] we get the file and disassemble it. Which after reversing the file it looks like

3: http://overthewire.org/wargames/vortex/vortex8.bin

so when this runs it will create a thread that loops and prints 0 every second, flushes stdout, and sleeps for 1u, in the main thread it will SYS_setresgid() the current GID, and SYS_setresuid() the current UID. Then goes into unsafecode() which is a stack overflow. This shows two things. That the thread is running in a different uid than the one executing before it ran before resetting gid, and uid. Thus our attack should be targeted to the thread. When we look at the thread, safecode() we see that it uses printf, fflush, and sleep functions those which execute in a forever loop. We can attack those functions to control the execution getting a shell in the first thread context meaning getting execution for the targeted uid,gid we want to go to the next level.

First we determine what we can write to and what we control.

then we find our 0x41's at the stack somewhere near 0xffffd541 so what I'm thinking of is jumping there were we will have a shellcode that will overwrite got.plt of fflush, so the not so safe thread will jump to a controlled place when it calls fflush

.got.plt:0804A00C off_804A00C dd offset fflush

this is the first shellcode that does this.

then we processed with something similar to

[0x90s][overwrite fflush got sh][0x90s][/bin/sh]

after the overwriting of fflush@got.plt with an address pointing to the second nops the main thread will call /bin/sh shellcode when it executes fflush.

next..

Level9

This one was pretty simple, password is at /var/mail/vortex9

Level10

Read in 20 integers and write the seed used to generate those numbers in unsigned little endian format. You have a time limit of 30 seconds to do this. You must login to vortex.labs.overthewire.org

After connecting I found a binary scp'd it and started reverse engineering it.

image

this is how main looks like. So we need to find the actual seed to win, but we only given 10 random numbers, and 30 seconds to enter the seed :). This 30 second is enough I guess. Let us look at how the seed is generated.

So the seed actually is something like the following

So seed is time in seconds since Epoch 1970-01-01 00000...etc plus a. Here a is a value bounded in [-128,128]. To find the seed we need to use this information. We generate a list of seeds [-128,128]+time(NULL); That's 256 seeds. Second thing is the generated sequenceses aren't from the beginning of the random stream. It's from [0,(positive)a]. So we need also to take care of this.

First we create a wrapper that will print time(NULL) and execute vortex10 so we know the value used for seed.

then we write the exploit

This will read the leaked seed from the wrapper, and the first random value. Then try to find the a value that was added to the leaked seed if such value is found then we use leaked_seed+a as the seed that was used by the level.

next

Level11

You must corrupt the heap in order to gain arbitrary control of this program. Do recall, the application is using phkmalloc.

The malloc here uses phkmalloc an implementation written by Poul-Henning Kamp for Freebsd. We compile this in our machine break at exit and try to gather information about it.

we'll be overwriting s from r since we can do that. Let's see what s is

so we see the pginfo struct of s. We overwrite stuff and see what happens to the above structure.

so we see that we control page and next for the allocated page of s at this point we see that we have segfaulted in strncpy.

from here we see that edi == page, xmm0.v4_int32 is at offset 2056 (in argv[2]). So we can write anything v4_int32 in xmm0 to any edi pointer. Let's see exit@got.plt since this will be called after strncpy finishes :) so when it calls exit it'll be calling our evil exit.

this 0x0804b5d4-0x40 is the pointer we want to write. the +0x40 that comes into edi is from the malloc thingy so we have to subtract that value to get the exact address we want as you see from above edi points to the address we want plus 0x40.

This all looks perfect let us exploit it in vortex machine now. I find that exit pointer at 0x0804c01c-0x40==0x0804bfdc.

I will just stop here and continue the solutions to the next levels sometime soon in another post.

Proxied content from gemini://0x80.org/gemlog/2014-07-25-solving-overthewire.gmi.
Get a proper gemini browser and visit!

Gemini request details:

Original URL
gemini://0x80.org/gemlog/2014-07-25-solving-overthewire.gmi
Status code
20
Meta
text/gemini;lang=en-US