Level 0
Drifter can be accessed on drifter.labs.overthewire.org (69.55.233.89). 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
- 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.
- Examine how the RC4 keys are generated, and how they are applied
- 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.
- 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"
- Write the filename ("instructions" sans quotes) to the allocated memory location to your client socket
- open() the "instructions" file. You will get the fd it was allocated to in response
- read() from the allocated file descriptor to your allocated memory
- 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.
-
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:
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 }