OverTheWire
We're hackers, and we are good-looking. We are the 1%.
Discuss this level on the forum

Level 0

Drifter can be accessed on drifter.labs.overthewire.org. Level 0 listens on port 1111.

Level0 is an extremely trivial, encrypted, remote syscall proxy. Your aim is to read the contents of a file called "instructions" to get the username / password contents.

Upon connection, it sets up an encrypted rc4 key (based on the connecting IP address / port), read()'s in 9 integers, and then decrypts them, and handles them off to syscall(). This allows the network client to execute arbitrary syscalls in a safe way.

To give you an idea of what's needed:

You'll need to

  1. If you are behind a NAT/PAT, you might want to do vortex level0, and complete this level from vortex, as otherwise your known IP address and port information changes.
  2. Examine how the RC4 keys are generated, and how they are applied
  3. mmap2() some memory. You will get the address where the memory was allocated in the response from the server. mmap2() takes its arguments from registers, not the stack.
  4. read() into that allocated buffer to get the file name. The source fd that you need will be 4. (0-2 = stdin/stdout/stderr, 3 will be network socket, so 4 in next in line. You will want to read in enough data for the filename "instructions"
  5. Write the filename ("instructions" sans quotes) to the allocated memory location to your client socket
  6. open() the "instructions" file. You will get the fd it was allocated to in response
  7. read() from the allocated file descriptor to your allocated memory
  8. write() from the allocated buffer to the socket on the server (fd 4)

Once all that is done, you will have the contents of the instructions file printed to your screen.

Of course - this does not prevent you from using other mechanisms to access the server, such as using "shelldemo" from metasploit 2.x to examine the environment. In fact, using shelldemo is probably a good exercise as well.

In order to get the values for the parameters you need, you can use cross-references of linux code on the net, for example, to look up the value for __NR_read (linux read syscall()), we can use this which will lead us to http://lxr.linux.no. From there we can use the search facility to find the values we need, such as:

#define __NR_read 3

If this level is too complicated / involved, please leave a comment. While it's complicated than adding several little endian integers together, I don't want the initial level to be overkill.

-

Code listing (level0.c)
  1 /*
  2  * Level 0 for drifter - Jan 16th, 2008
  3  *
  4  * This is an extremely simple / stupid remote procedure call implementation
  5  * that allows system calls and parameters to be supplied directly, and
  6  * return codes written to the caller.
  7  *
  8  * For security reasons, it is chrooted and drops privileges, and in addition,
  9  * the connection is encrypted. (The previous sentence is a joke..)
 10  *
 11  * In the chroot directory, there is a file called 'instructions', open that,
 12  * read the contents, and you'll know what to do next.
 13  *
 14  * In order to make things easier for yourself, there is plenty of tools
 15  * out there already - I suggest that you read up and learn about them.
 16  *
 17  * - a scripting language (I humbly suggest Python, but whatever you're most
 18  *   comfortable with)
 19  * - <a href="http://oss.coresecurity.com/projects/inlineegg.html
 20  " title="http://oss.coresecurity.com/projects/inlineegg.html
 21  ">http://oss.coresecurity.com/projects/inlineegg.html
 22  </a> * - mosdef - <a href="http://www.immunitysec.com/resources-freesoftware.shtml
 23  " title="http://www.immunitysec.com/resources-freesoftware.shtml
 24  ">http://www.immunitysec.com/resources-freesoftware.shtml
 25  </a> * - <a href="http://archives.neohapsis.com/archives/vuln-dev/2003-q4/0006.html
 26  " title="http://archives.neohapsis.com/archives/vuln-dev/2003-q4/0006.html
 27  ">http://archives.neohapsis.com/archives/vuln-dev/2003-q4/0006.html
 28  </a> * - metasploit.com
 29  * - Plenty of other things :)
 30  *
 31  * To compile this code, gcc level0.c rc4.c -o /drifter/level0
 32  */
 33 
 34 #include <stdlib.h>
 35 #include <unistd.h>
 36 #include <stdio.h>
 37 #include <sys/socket.h>
 38 #include <fcntl.h>
 39 #include <string.h>
 40 #include <sys/syscall.h>
 41 #include <signal.h>
 42 #include <netinet/in.h>
 43 #include <netinet/tcp.h>
 44 
 45 #include "rc4.h"
 46 
 47 void setup_stuff()
 48 {
 49     /* Become a daemon, and drop privileges, chroot off, etc. */
 50 
 51     signal(SIGCHLD, SIG_IGN); // ignore children.. seems to work :p
 52 
 53     if(daemon(0, 0) != 0) exit(1);
 54 
 55     if(chroot("/home/drifter/drifter0/chroot") != 0) exit(2);
 56     if(chdir("/") != 0) exit(3);
 57 }
 58 
 59 void dropprivs()
 60 {
 61     int groups[1];
 62 
 63 #define LEVEL0 1000
 64     groups[0] = LEVEL0;
 65     if(setgroups(1, groups) != 0) exit(15);
 66     if(setresgid(LEVEL0, LEVEL0, LEVEL0) != 0) exit(4);
 67     if(setresuid(LEVEL0, LEVEL0, LEVEL0) != 0) exit(5);
 68 #undef LEVEL0
 69 }
 70 
 71 int create_socket()
 72 {
 73     /* Create / bind / listen on socket */
 74 
 75     int ret;
 76     struct sockaddr_in sin;
 77 
 78     ret = socket(AF_INET, SOCK_STREAM, 0);
 79     if(ret == -1) exit(6);
 80 
 81     memset(&sin, 0, sizeof(struct sockaddr_in));
 82     sin.sin_family = AF_INET,
 83         sin.sin_addr.s_addr = htonl(INADDR_ANY);
 84     sin.sin_port = htons(1111);
 85 
 86     if(bind(ret, (void *)&sin, sizeof(struct sockaddr_in)) == -1) exit(7);
 87 
 88     if(listen(ret, 5) == -1) exit(8);
 89 
 90     return ret;
 91 
 92 }
 93 
 94 void handle_client(int skt, struct sockaddr_in *sin)
 95 {
 96     // Handle the client connection, and perform the requested operations.
 97 
 98     rc4_key key_in, key_out;
 99     unsigned char keymat[6];
100     unsigned int args[9];
101     int i, ret;
102 
103     dropprivs();
104 
105     memcpy(keymat, &(sin->sin_addr.s_addr), 4);
106     memcpy(keymat+4, &(sin->sin_port), 2);
107 
108     prepare_key(keymat, 6, &key_in);
109     prepare_key(keymat, 6, &key_out);
110 
111     for(i=0;i<42;i++) {
112         // cycle through first 256 bytes
113         rc4(keymat, 6, &key_in);
114         rc4(keymat, 6, &key_out);
115     }
116 
117     while(1) {
118         alarm(60);
119         sleep(1);
120 
121         if(read(skt, &args, sizeof(args)) != sizeof(args)) exit(EXIT_SUCCESS);
122 
123         rc4(&args, sizeof(args), &key_in);
124 
125         ret = syscall(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
126 
127         rc4(&ret, sizeof(int), &key_out);
128 
129         if(write(skt, &ret, sizeof(ret)) != sizeof(ret)) exit(EXIT_SUCCESS);
130 
131     }
132 
133 }
134 
135 void mainloop()
136 {
137     int skt;
138     int cli;
139     int so;
140     int ret;
141 
142     struct sockaddr_in sin;
143 
144     skt = create_socket();
145 
146     while(1) {
147         so = sizeof(struct sockaddr_in);
148         cli = accept(skt, (void *)&sin, &so);
149         if(cli == -1) exit(9);
150 
151         ret = fork();
152         if(ret == -1) exit(10);
153 
154         // parent
155 
156         if(ret) {
157             close(cli);
158             continue;
159         }
160 
161         // child
162         close(skt);
163         handle_client(cli, &sin);
164         exit(EXIT_SUCCESS);
165     }
166 }
167 
168 int main(int argc, char **argv)
169 {
170     setup_stuff();
171 
172     mainloop();    
173 }

Here is the rc4 code that I used:

Code listing (rc4.c)
 1 void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key *key)
 2 {
 3     int i;
 4     unsigned char t;
 5     unsigned char swapByte;
 6     unsigned char index1;
 7     unsigned char index2;
 8     unsigned char* state;
 9     short counter;
10 
11     state = &key->state[0];
12     for(counter = 0; counter < 256; counter++)
13         state[counter] = counter;
14     key->x = 0;
15     key->y = 0;
16     index1 = 0;
17     index2 = 0;
18     for(counter = 0; counter < 256; counter++)
19     {
20         index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
21         swap_byte(&state[counter], &state[index2]);
22         index1 = (index1 + 1) % key_data_len;
23     }
24 }
25 
26 void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key)
27 {
28     unsigned char t;
29     unsigned char x;
30     unsigned char y;
31     unsigned char* state;
32     unsigned char xorIndex;
33     short counter;
34 
35     x = key->x;
36     y = key->y;
37     state = &key->state[0];
38     for(counter = 0; counter < buffer_len; counter++)
39     {
40         x = (x + 1) % 256;
41         y = (state[x] + y) % 256;
42         swap_byte(&state[x], &state[y]);
43         xorIndex = (state[x] + state[y]) % 256;
44         buffer_ptr[counter] ^= state[xorIndex];
45     }
46     key->x = x;
47     key->y = y;
48 }