Archive for the 'Windows' Category

Blackhat USA 2007 (Presentation Material)

mark August 7th, 2007

Hi!

Well, we just arrived home from Las Vegas on Sunday after delivering our talk at Blackhat about breaking C++ applications. It seemed to be received pretty well. For anyone interested, the slides should be available on their website, but we have also archived them here.

Enjoy!

String Theory (..for Windows)

mark January 9th, 2007

In languages that have direct memory access, string manipulation has always been tough to get right. When the dangers of buffer overflows were first realized, many applications that did any sort of string processing were found to have vulnerabilities that we would now consider to be obvious. Over the years, system string APIs have been updated, refined, and replaced. Interestingly, these various replacement functions have exhibited additional quirks, which can render an application vulnerable in more subtle ways than with standard buffer overflows. Some of these quirks are quite well-documented and well-known (such as the strncpy() function not NUL-terminating), and some of them are not. Windows actually provides quite a large number of string functions, each with their own subtle variances. It is important as auditors to know these differences so that you can accurately assess whether an application is vulnerable to potential memory corruption issues or not. With that in mind, I’ve put together a series of tables of quick facts about the various string functions available in a Win32 programming environment that should be useful as a reference when auditing string manipulation routines.

Continue Reading »

Attacking delete and delete [] in C++

blog January 3rd, 2007

In C++, objects can be dynamically allocated at runtime using the new operator and deallocated using the delete operator. Arrays of objects, however, require the use of slightly different operators for allocation and deallocation: new [] and delete []. Although the corresponding pairs of operators look very similar in source code, the way they function is actually quite different. Consequently, they can’t be mixed and matched - allocating an array with new [] and then deallocating it with delete, for example, will produce "undefined" results. This can catch developers off-guard, because you can often use the wrong operator without triggering a compiler warning or even causing a run-time crash.
Continue Reading »

SQL Injection/Truncation in Stored Procedures

mark December 27th, 2006

SQL injection vulnerabilities have plagued applications for many years. When a dynamic SQL query is constructed with any sort of user-controllable input, there exists the potential for an attacker to perform arbitrary SQL queries, which might lead to sensitive information disclosure or modification. Developers wanting to protect their applications from these kinds of attacks have typically instituted filtering of user data for SQL metacharacters, moved their database query code into stored procedures, or replaced their dynamic SQL statements with prepared SQL. Prepared SQL statements are precompiled SQL queries that accept user-defined parameters without allowing for SQL injection attacks to occur. Since the SQL query is compiled beforehand, the user’s data is never parsed by the SQL parser, and thus isn’t capable of triggering metacharacter attacks.
Continue Reading »

Fun With Impersonation

justin December 19th, 2006

Here’s our first "Spot the Vuln" challenge. I originally put this together for a post to Matasano’s blog, but work got pretty hectic and I had to let it slip for a bit. Now I finally have a little breathing room, so I thought this would be a good place to post it.

The below function is a thread spawned from a named pipe server in Windows. The io parameter is an open named pipe handle returned from a call to ConnectNamedPipe(); data has been read from the pipe, so impersonation shouldn’t fail.

int tclient(HANDLE io) {
     int hr = 0;
     STARTUPINFO si;
     PROCESS_INFORMATION pi;

HANDLE hProc = GetCurrentProcess();
if(!ImpersonateNamedPipeClient(io)) return GetLastError();
ZeroMemory(&si, sizeof(si)); si.dwFlags = STARTF_USESTDHANDLES; si.cb = sizeof(si); DuplicateHandle(hProc, io, hProc, &si.hStdInput, GENERIC_READ, TRUE, 0); DuplicateHandle(hProc, io, hProc, &si.hStdOutput, GENERIC_WRITE, TRUE, 0); DuplicateHandle(hProc, io, hProc, &si.hStdError, GENERIC_WRITE, TRUE, 0); CloseHandle(io);
CreateProcess(NULL, SHELL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); CloseHandle(si.hStdError);
hr = RevertToSelf();
if (pi.hProcess != NULL) WaitForSingleObject(pi.hProcess, INFINITE);
return hr; }

This post is open for comments, but we will be moderating first because we don’t want to spoil the fun for everyone.

HANDLE with care

justin December 5th, 2006

I made a very poorly conceived last minute change to the description of object handles on page 632; this mistake can be blamed primarily on a lack of sleep and a broken test environment.  Basically, I wrote that you can use NtQuerySystemInformation() to retrieve unnamed object handles with weak permissions. The truth is that permissions don’t apply when duplicating open handles, which I explained properly elsewhere in the chapter.  The crux of this error is really that I failed to address the PROCESS_DUP_HANDLE permission and how it prevents exactly that attack vector.

Essentially, duplicating handles between processes requires PROCESS_DUP_HANDLE permissions for both the source and destination processes; otherwise the call to DuplicateHandle() will fail with access denied.  This is important to note because having PROCESS_DUP_HANDLE permission for another process allows you to duplicate that process’ pseudo-handle for itself. The resulting handle grants full rights to the target process, including arbitrary manipulation of memory.

In the end, I think we’ve all learned a really valuable lesson about trusting judgment calls when under the influence of deadlines.