RATS

The Rough Auditing Tool for Security (RATS), from Secure Software Inc., tries to help programmers smooth the rough edges of their C, C++, Perl, PHP, Python, or OpenSSL applications. Unlike Flawfinder, RATS is written in C and contains external XML collections of rules that apply to each language. RATS also took the "easy way out" by using a Lexer to tokenize source files before they are parsed by the main RATS engine.

Implementation

RATS compiles easily on most Unix systems, although you need to make sure that you have the Expat XML Parser installed (http:// sourceforge .net/projects/expat/). This is less of a problem on Linux systems because the major distributions have started including the library. Once Expat is installed, compilation is a ./configure and make away.

RATS 2.1 expands the tool's support and use of XML data, which makes it easier to write custom checks. Its usage remains relatively the same, but now a native Windows binary is available in addition to the original Unix version. Many of the command-line flags have synonymsfor example, d is equivalent to db or database . See the following table for more information about the available options.

 usage: rats [-adhilrwxR] [--help] [--database--db] name1 name2 ... namen 

RATS Option

Description

-a < fun >

Reports any occurrence of function "fun" in the source file(s)

-d < filename >

Specifies an alternative vulnerability database

-h

Displays usage information

-i

Reports functions that accept external input

-l < language >

Forces the specified language to be used

-r

Includes references that are not function calls

-w <1,2,3>

Sets warning level (the default is 2)

-x

Does not load default databases

-R

Does not recurse subdirectories scanning for matching files

xml

Outputs in XML

html

Outputs in HTML

follow- symlinks

Follows symlinks and processes files found

noheader

Does not print initial header in output

nofooter

Does not show timing information footer at end of analysis

quiet

Does not print status information regarding what file is being analyzed

resultsonly

No header, footer, or status information

columns

Shows column number of the line where the problem occurred

context

Displays the line of code that caused the problem report

name1 name2 namen

Files names of source code to audit, accepts wildcards

RATS assumes the file(s) are written in C, but it will switch its assumption based on limited filename extensions:

  • Perl .pl, .pm

  • PHP .php

  • Python .py, .PY

Use the l option to force C, Perl, Python, or PHP. The C and C++ checks use the same list of functions and syntax errors. The Perl, Python, and PHP language checks do not really examine idiosyncrasies of the particular language. The Perl checks, for example, focus on underlying system functions (meaning "C-equivalent" functions) as opposed to stringent checks on Perl syntax and variable management. You can still have a highly insecure web application built in Perl (or Python or PHP); RATS performs only basic checks. In RATS's defense, Perl's data types do not easily lend themselves to strong type checking and boundary tests, or are Perl scripts vulnerable to buffer overflows in the same sense as a C program.

One of the interesting additions to RATS is the rats-openssl.xml file that contains a list of common functions from the OpenSSL library and cautions for properly using, allocating, and referencing buffers. These are part of the C-language checks and would help anyone developing C or C++ web applications.

Note 

Perl provides a T option to " taint " variables. Perl never passes tainted variables to a system function (such as exec ). This accomplishes the majority of the input validation tests for shell metacharacters normally required in a secure program, but it is far from adequate especially in web applications.

The a and d options come in handy for extending RATS. Use a to instruct RATS to make grep-like searches for a particular function. The d option is even more useful, but you will have to be comfortable with XML syntax. For example, here's one of RATS's check structures on the tmpfile function:

 <!ENTITY tmpfile "Many calls for generating temporary file names are insecure (susceptible to race conditions). Use a securely generated file name, for example, by pulling 64 bits of randomness from /dev/random, base 64 encoding it and using that as a file suffix."> 

Within the six new Windows-specific checks is the equivalent temporary file caution:

 <!ENTITY w32tmppath "GetTempPath() may return the current directory or the windows directory. Be careful what you place in these locations. Important files may be overwritten, and trojan DLL's may be dropped in these locations. Never use a user-input filename when writing to a location given by GetTempPath()."> 

Other checks cover Windows-specific functions such as pathbuf , dllload , and w32exec . Note that just looking for the existence of a function probably causes more false positives than necessary, but it serves to highlight potential problem areas.

Case Study: wu- ftpd 2.6.0

The Washington University FTP server suffered growing pains during its evolution from version 2.4 through 2.6. One of the vulnerabilities brought to Bugtraq's attention by tf8@zolo.freelsd.net (Bugtraq ID 1387) belonged to a class of vulnerabilities based on format strings. Flawfinder contains a catalog of misused functions and reports every one it finds:

 $ flawfinder ftpd.c flawfinder version 0.21, (C) 2001 David A. Wheeler. Number of dangerous functions in C ruleset: 55 Examining ftpd.c?ftpd.c:5593 [5] (race) chown: this accepts filename arguments; if an attacker can move those files, a race condition results. . Use fchown() instead. ftpd.c:412 [4] (format) vsnprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification. ftpd.c:416 [4] (format) snprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification. ftpd.c:684 [4] (buffer) strcpy: does not check for buffer overflows. Consider using strncpy or strlcpy.  ftpd.c:3158 [4] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf. ftpd.c:5890 [4] (buffer) sprintf: does not check for buffer overflows. Use snprintf or vsnprintf.  ftpd.c:6160 [4] (format) syslog: if syslog's format strings can be influenced by an attacker, they can be exploited. Use a constant format string for syslog. ftpd.c:6618 [4] (format) vsnprintf: if format strings can be influenced by an attacker, they can be exploited. Use a constant for the format specification. 

The four lines in boldface type correspond to these lines in the source code:

 sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); ... sprintf(proctitle, "%s: connected", remotehost); 

The actual exploit affected the lines immediately following the sprintf functions, but this shows how Flawfinder may point you in the right direction for tracking down programming errors. For example, part of the patch released to fix the format string error looks like this (a - at the beginning of a line means to delete the line; a + means to add it):

 remotehost[sizeof(remotehost) - 1] = ' 
 remotehost[sizeof(remotehost) - 1] = '\0'; sprintf(proctitle, "%s: connected", remotehost); -setproctitle(proctitle); +setproctitle("%s", proctitle); 
'; sprintf(proctitle, "%s: connected", remotehost); -setproctitle(proctitle); +setproctitle("%s", proctitle);
 
Case Study: What Automated Audit Tools Miss

Automated tools understand the syntax rules of a programming language. They detect problems inherent to a specific function or how that function is commonly misused. Automated tools cannot find or solve logic-based problems in source code. Logic-based problems involve arithmetic, Boolean comparisons, and variable substitution.

Integer Mismatches In C and C++ applications, programmers store numeric variables in a variety of formats: 16-bit, 32-bit, signed (may have negative values), or unsigned (positive values only). OpenSSH was vulnerable to a CRC-32 compensation attack, discovered by Michal Zalewski (Bugtraq ID 2347), that exploited a problem with the storage of two mismatched numeric variables. The vulnerability required only a one-line fix to change a variable n from a 16-bit value to a 32-bit value:

 - static word16  n = HASH_MINSIZE / HASH_ENTRYSIZE; + static word32  n = HASH_MINSIZE / HASH_ENTRYSIZE; 

This value was used later in a FOR loop that operated on a 32-bit value, l :

 u_int32_t l;  for  (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE);  l  =  l << 2  ); if (h == NULL) {   debug("Installing crc compensation attack detector.");  n = l;  h = (u_int16_t *) xmalloc(n * HASH_ENTRYSIZE); } 

The value for n was initially 4096. The FOR loop would multiply l by 2 ( l=l<<2 ) until it passed a certain limit. It was possible for l to reach a value of 65536; however, the maximum value for a 16-bit number is only 65535. Consequently, n would be set to zero. This did not affect the Secure Shell (SSH) until another FOR loop used the value for a later function:

 register u_int32_t i; for (i = HASH(c) &  (n - 1)  ; h[i] != HASH_UNUSED; 

If n equals zero, then n1 equals 1 , but to an unsigned 32-bit integer 1 looks like 0xFFFFFFFF in hexadecimal notation (it cannot be negative). In other words, HASH(c) & (n-1) becomes HASH(c) , a value that an attacker can manipulate.

Boolean Tests Logical tests and implied boundary values also lead to errorsbut errors that cannot be found automatically. For example, the OpenSSH Channel Code Off-By-One vulnerability (Bugtraq ID 4241) discovered by Joost Pol is due to a subtle error in checking a numeric boundary. Take a look at the vulnerable code (the first line) and the fix (the second line):

 - if (id < 0  id  >  channels_alloc) { + if (id < 0  id  >=  channels_alloc) { 

The whole IF statement looks like this:

 if (id 0  id >= channels_alloc) {            log("channel_lookup: %d: bad id", id);            return NULL;      }      c = channels[id]; 

The vulnerable IF statement does not execute if the id value equals the chan-nels_alloc limit. This causes problems in the next command, when the program tries to call the channels[id] array.

Precompiled Binaries A source-code auditing tool cannot audit a binary executable. Truisms aside, this drives home the fact that good security must rely on up-to-date patch levels, host configurations that follow least-privilege design, and strong network controls. For example, consider the .ida buffer overflow in Microsoft IIS:

  • Patch level It was a zero-day exploit, so users had to wait for Microsoft to release a patch. Of course, the vulnerability is still being exploited six months later, pointing to other problems with configuration management or lack of user education.

  • Host security If users had removed unused ISAPI filters.ida in particularthe vulnerability would not have been accessible. If the application had been shipped in a least-privilege state (for example, users add ISAPI filters as they need them), users would not have had this problem in the first place. How many users needed the .printer extension (which also had a buffer overflow)?

  • Network security Affected many organizations' servers that belonged to test networks, internal networks that erroneously permitted incoming web traffic, or servers deployed without acknowledgment of the security group .

Even if you have access to source code, you may still be unable to identify security holes. You can, however, apply methods from each of the three preceding concepts to block or at least mitigate security vulnerabilities in the software on your network.

Auditing compiled programs for buffer overflows is not impossible , but it requires a greater understanding of memory and processor architectures. No serious commercial tools or open -source projects are publicly available that automatically search for common problems within a binary. Usually, the only tools necessary are a pad of paper, a few pencils, and a debugger. The tools are simple, but the techniques are more difficult and beyond the scope of this book.

 
Case Study: mtr 0.46

MTR is a General Public License (GPL) tool that combines the functionality of traceroute and Ping. Damian Gryski identified a buffer overflow condition in the way MTR handles the MTR_OPTIONS environment variable (Bugtraq ID 4217). Environment variables have a long history as attack vectors for buffer overflows. Thus, it's no surprise that RATS checks for functions that use environment variables.

 $ rats mtr.c mtr.c:72: High: getopt_long Truncate all input strings to a reasonable length before passing them to this function mtr.c:139: High: fixed size local buffer Extra care should be taken to ensure that character arrays that are allocated on the stack are used safely. They are prime targets for buffer overflow attacks.  mtr.c:180: High: getenv Environment variables are highly untrustable input. They may be of any length, and contain any data. Do not make any assumptions regarding content or length. If at all possible avoid using them, and if it is necessary, sanitize them and truncate them to a reasonable length.  mtr.c:185: High: printf mtr.c:190: High: printf Check to be sure that the non-constant format string passed as argument 1 to this function call does not come from an untrusted source that could have added formatting characters that the code is not prepared to handle. mtr.c:236: High: gethostbyname DNS results can easily be forged by an attacker (or arbitrarily set to large values, etc.), and should not be trusted. 

Here's the line of code that generated the finding in RATS (the same line could have been found with a grep getenv mtr.c command):

 parse_mtr_options (getenv ("MTR_OPTIONS")); 

RATS identified a potential vulnerability. It is up to the auditor to trace the vulnerability into the parse_mtr_options function and determine whether or not the finding is valid. Przemyslaw Frasunek crafted an exploit that illustrated how the parse_mtr_options function mishandled the MTR_OPTIONS variable. Here's the section of the vulnerable code:

 while (  p  ) {     argv[argc++] = p;     p = strtok (NULL, " \t"); } 

The p variable is a pointer to the memory location that could contain not only the value of the MTR_OPTIONS environment variable, but also the data that could be placed into memory and used to execute arbitrary commands. The strtok C function operates on strings stored in memory, looking for patterns specified in its second argument ( " \t" or a space and tab character combination in this example). When strtok receives a NULL value for its first argument, it operates on the current pointer, in this case p . However, an attacker could craft a malicious MTR_OPTIONS that causes the pointer to be overwritten with shellcodein other words, execute an arbitrary command.

The author's patch implements a length check on the p variable and reports extraneous data:

 while (p &&  (argc < (sizeof(argv)/sizeof(argv[0])))  ) {     argv[argc++] = p;     p = strtok (NULL, " \t"); } if (p) {     fprintf (stderr, "Warning: extra arguments ignored: %s", p); } 

An audit from RATS and a follow-through on the recommendation, "Do not make any assumptions regarding content or length," would have negated the attack.

 
Case Study: Copying Unsafe Data

In September 2005 an advisory was released that described a vulnerability in the snort intrusion detection system that could be exploited to cause a denial of service. A nicely detailed summary can be found at http://www.vulnfact.com/advisories/snort_adv.html. This vulnerability illustrates the challenge in analyzing source code for proper implementation of bounds checking. In this instance, the problematic function was a memcpy () that assumed the source data was of a reliable length.

Flawfinder can lead us to the vulnerable section, but it won't necessarily indicate what the problem is. All it can do is hint that the memcpy() function is often misused.

 [Paris:snort-2.4.0/src] mike% flawfinder log.c log.c:1525: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. log.c:1543: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. log.c:1546: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. 

Inspecting the relevant lines shows us how the function is used, but doesn't immediately highlight the problem:

 case TCPOPT_SACK:                 bzero((char *) tmp, 5);                 memcpy(tmp, p->tcp_options[i].data, 2);                 fprintf(fp, "Sack: %u@", EXTRACT_16BITS(tmp));                 bzero((char *) tmp, 5);                 memcpy(tmp, (p->tcp_options[i].data) + 2, 2); 

One step would be to track down the p->tcp_options structure (in src/decode.h) and inspect its contents to get an idea of what it contains and what size the tcp_options is. The assumption is that the i variable refers to the number of options specified in the packet. Look at line 1510:

 for(i = 0; i < (int) p->tcp_option_count; i++) 

This assumption should be valid when packets are well- formed , but a specially crafted packet might define more options than are actually present.

Now let's turn to the log.c file that was patched in snort version 2.4.1. Flawfinder's output is identical, although line numbers have changed a bit:

 log.c:1529: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. log.c:1551: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. log.c:1555: [2] (buffer) memcpy:  Does not check for buffer overflows when copying to destination.  Make sure destination can always hold the source data. 

Flawfinder still indicates the potentially misused function. Yet if we look at the source code, we can see how the vulnerability was addressed:

 case TCPOPT_SACK:                 bzero((char *) tmp, 5);                 if (p->tcp_options[i].data)                     memcpy(tmp, p->tcp_options[i].data, 2);                 fprintf(fp, "Sack: %u@", EXTRACT_16BITS(tmp));                 bzero((char *) tmp, 5);                 if (p->tcp_options[i].data)                     memcpy(tmp, (p->tcp_options[i].data) + 2, 2); 

The data will only be copied if there is non-null content in the array. This small step prevents snort from crashing. Most source code analysis tools won't be able to fully interpret the code and identify a vulnerability, but they can point out areas of interest.

As a final note, it should be noted that this particular vulnerability was identified by injecting randomly formed packets into snort and monitoring its behavior. Thus, no source code was necessary to initially discover the vulnerability. However, the availability of source helped to quickly identify (and exploit) the problem as well as develop a solution.

 
Case Study: Canaries in the Mist

In the opening paragraph of this chapter, we wished for a compiler that would create the " unbreakable " application. Stackguard, from http://immunix.org, is a collection of patches to the GCC compiler. (Immunix was acquired by Novell, which now combines Stackguard in a commercial product.) These patches turn GCC into a proactive "securifier" of any C or C++ code that it compiles.

The basic concept is that function calls potentially vulnerable to buffer overflows have "canaries" (random values) appended to their memory space. When an attacker attempts a buffer overflow, the attack corrupts the memory space that contains the canary. The program recognizes that the canary has been modified and abruptly haltswithout executing any malicious code inserted by the attacker.

We would only echo the excellent Stackguard documentation to describe the buffer overflow protection in adequate detail. Check out the http://immunix.org web site for more information.

The OpenBSD and Linux kernel developers have both started projects that will attempt to stop the most common buffer overflows. To give an unfairly simple description of their techniques, the OpenBSD group is separating the read, write, and execute permissions on the memory pages made available to a program. So if a buffer overflow vulnerability were present, but the memory was read-only or nonexecutable, the exploit would fail. The Linux gr- security patch provides similar mechanisms for blocking stack execution as well as strict access control lists for programs.

Keep in mind that Stackguard and "nonexecutable stack" settings are not a panacea for buffer overflows. There are documented techniques for circumventing many Stackguard-like protections . Secure your network, your host, and then the applicationredundancy always helps.

If you're more interested in secure coding, you may be interested in a few of these links:

  • .NET Secure Coding Guidelines, at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconsecurecodingguidelines.asp

  • Reviewing Code for Integer Manipulation Vulnerabilities, at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html/secure04102003.asp

  • Secure Programming HOWTO, at http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO.html

 


Anti-Hacker Tool Kit
Anti-Hacker Tool Kit, Third Edition
ISBN: 0072262877
EAN: 2147483647
Year: 2006
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net