xorl %eax, %eax

CVE-2009-2288: Nagios CGI Arbitrary Command Execution

leave a comment »

This vulnerability affects Nagios prior to 3.1.1. Specifically, statuswml CGI script does not perform sufficient checks in the user controlled input. Here is the vulnerable code as seen in 3.1.0 release of Nagios.

/* displays ping results */
void display_ping(void){
	char input_buffer[MAX_INPUT_BUFFER];
	char buffer[MAX_INPUT_BUFFER];
	char *temp_ptr;
	FILE *fp;
	int odd=0;
	int in_macro=FALSE;
       ...
			for(temp_ptr=my_strtok(input_buffer,"$");temp_ptr!=NULL;temp_ptr=my_strtok(NULL,"$")){
       ...
					if(strlen(buffer)+strlen(temp_ptr) < sizeof(buffer)-1){

						if(!strcmp(temp_ptr,"HOSTADDRESS"))
							strncat(buffer,ping_address,sizeof(buffer)-strlen(buffer)-1);
					        }
       ...
			/* run the ping command */
			fp=popen(buffer,"r");
       ...
	return;
        }
&#91;/sourcecode&#93;

This code can be found at cgi/statuswml.c file. As you can see, there is no check on the host address passed to the PING option of that CGI script. Because of this missing check, a user is able to use command seperation characters such as ';' (hex value 0x3B) to execute arbitrary commands. In the original report there was an example which was:

https://somehost.com/nagios/cgi-bin/statuswml.cgi?ping=173.45.235.65%3Becho+%24PATH 

This will return the contents of PATH environment variable since 0x3B is equal to ';' character and 0x24 is the '$' sign. The same vulnerability was also present in display_traceroute() function of the same CGI. To fix this, the Nagios developers wrote two new functions which you can see here:

&#91;sourcecode language="c"&#93;
int validate_arguments(void){
       int result=OK;
       if((strcmp(ping_address,"")) && !is_valid_hostip(ping_address)) {
               printf("<p>Invalid host name/ip</p>\n");
               result=ERROR;
               }
       if(strcmp(traceroute_address,"") && !is_valid_hostip(traceroute_address) ){
               printf("<p>Invalid host name/ip</p>\n");
               result=ERROR;
               }
       return result;
       }

Which uses is_valid_hostip() function to validate the given IP address. is_valid_hostip() is the second function that was added and it simply does this:

int is_valid_hostip(char *hostip) {
       char *valid_domain_chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTVWXYZ0123456789.-";
       if(strcmp(hostip,"") && strlen(hostip)==strspn(hostip,valid_domain_chars ) && hostip[0] != '-' && hostip[strlen(hostip)-1] != '-')
               return TRUE;
       return FALSE;
       }

It checks that there are no characters apart from those declared in valid_domain_chars array. At last, the main() function was updated to include the check like this.

        document_header();

+       /* validate arguments in URL */
+       result=validate_arguments();
+       if(result==ERROR){
+               document_footer();
+               return ERROR;
+               }
+
        /* read the CGI configuration file */

Written by xorl

July 3, 2009 at 13:52

Posted in bugs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s