Pregunta

Estoy trabajando en una página web ASP que maneja la carga de archivos. Solo se permite cargar ciertos tipos de archivos, como .XLS, .XML, .CSV, .TXT, .PDF, .PPT, etc.

Tengo que decidir si un archivo realmente tiene el mismo tipo que muestra la extensión. En otras palabras, si se cambió el nombre de un trojan.exe a harmless.pdf y se cargó, la aplicación debe poder descubrir que el archivo cargado NO es un archivo .PDF.

¿Qué técnicas usarías para analizar estos archivos cargados? ¿Dónde puedo obtener la mejor información sobre el formato de estos archivos?

¿Fue útil?

Solución

Una forma sería verificar ciertas firmas o números mágicos en los archivos. Esta página tiene una lista práctica de firmas de archivos conocidas y parece bastante actualizada:

http://www.garykessler.net/library/file_sigs.html

Otros consejos

  

En otras palabras, si un trojan.exe se renombró a harmless.pdf y se cargó, la aplicación debe poder descubrir que el archivo cargado NO es un archivo .PDF.

Eso no es realmente un problema. Si se cargó un .exe como .pdf y usted lo entregó correctamente al descargador como application / pdf, todo el descargador sería un PDF roto. Tendrían que volver a escribirlo manualmente en .exe para hacerse daño.

Los problemas reales son:

  1. Algunos navegadores pueden oler el contenido del archivo y decidir que saben mejor que usted sobre qué tipo de archivo es. IE es particularmente malo en esto, tiende a preferir renderizar el archivo como HTML si ve alguna etiqueta HTML al acecho cerca del inicio del archivo. Esto es particularmente inútil, ya que significa que el script se puede inyectar en su sitio, lo que puede comprometer la seguridad a nivel de aplicación (robo de cookies, etc.). Las soluciones alternativas incluyen siempre servir el archivo como un archivo adjunto utilizando Content-Disposition y / o servir archivos de un nombre de host diferente, por lo que no puede volver a hacer un script cruzado del sitio en su sitio principal.

  2. ¡Los archivos PDF no son seguros de todos modos! Pueden estar llenos de secuencias de comandos y han tenido importantes agujeros de seguridad. La explotación de un agujero en el complemento del navegador del lector de PDF es actualmente uno de los medios más comunes para instalar troyanos en la web. Y no hay casi nada que pueda hacer para tratar de detectar las vulnerabilidades, ya que pueden estar muy ofuscadas.

Obtenga los encabezados de los archivos de "seguro" tipos de archivos: los ejecutables siempre tienen sus propios tipos de encabezados, y probablemente pueda detectarlos. Sin embargo, debe estar familiarizado con todos los formatos que tiene la intención de aceptar.

Sé que dijiste C #, pero esto podría ser portado. Además, tiene un archivo XML que ya contiene muchos descriptores para tipos de archivos comunes.

Es una biblioteca Java llamada JMimeMagic. Está aquí: http://jmimemagic.sourceforge.net/

En los sistemas ** NIX * tenemos una utilidad llamada archivo (1) . Intenta encontrar algo similar para Windows, pero la utilidad de archivo si self ha sido portado.

Tal vez podrías abordar esto desde una dirección diferente. En lugar de identificar todos los tipos de archivos que se cargan (Excel solo me parece un desastre, porque tiene varios formatos en estos días), ¿por qué no ejecuta todas las cargas a través de un escáner de virus ? Una amplia variedad de archivos puede contener virus y troyanos. Puede ser más trabajo para su servidor, pero es la solución más segura.

Luego, corresponde a los usuarios identificar correctamente sus tipos de archivos, lo que parece razonable. Agregar un montón de código (que también tendrá que ser probado) solo para verificar a sus usuarios parece un gran paso. Si digo que es un archivo .pdf2, ¿le cambiará el nombre a .pdf? Si esto es en un entorno corporativo, entonces es razonable esperar que los usuarios tengan extensiones correctas en sus archivos. También rastrearía quién subió qué. Si es público, entonces valdría la pena buscar tipos de archivos, pero también haría el análisis de virus.

El siguiente código de C ++ podría ayudarlo:

//-1 : File Does not Exist or no access
//0 : not an office document
//1 : (General) MS office 2007
//2 : (General) MS office older than 2007
//3 : MS office 2003 PowerPoint presentation
//4 : MS office 2003 Excel spreadsheet
//5 : MS office applications or others 
int IsOffice2007OrOlder(wchar_t * fileName)
{
    int iRet = 0;
    byte msgFormatChk2007[8]    = {0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00};     //offset 0 for office 2007 documents
    byte possibleMSOldOffice[8] = {0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1};     //offset 0 for possible office 2003 documents

    byte msgFormatChkXLSPPT[4]  = {0xFD, 0xFF, 0xFF, 0xFF};     // offset 512: xls, ppt: FD FF FF FF 
    byte msgFormatChkOnlyPPT[4] = {0x00, 0x6E, 0x1E, 0xF0};     // offset 512: another ppt offset PPT   
    byte msgFormatChkOnlyDOC[4] = {0xEC, 0xA5, 0xC1, 0x00};     //offset 512: EC A5 C1 00 
    byte msgFormatChkOnlyXLS[8] = {0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00};     //offset 512: XLS

    int iMsgChk = 0;
    HANDLE fileHandle = CreateFile(fileName, GENERIC_READ,
        FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL  );
    if(INVALID_HANDLE_VALUE == fileHandle) 
    { 
        return -1; 
    }

    byte buff[20];
    DWORD bytesRead;
    iMsgChk = 1;
    if(0 == ReadFile(fileHandle, buff, 8, &bytesRead, NULL )) 
    { 
        return -1; 
    }

    if(buff[0] == msgFormatChk2007[0]) 
    {
        while(buff[iMsgChk] == msgFormatChk2007[iMsgChk] && iMsgChk < 9)
            iMsgChk++;

        if(iMsgChk >= 8) {  
            iRet = 1; //office 2007 file format
        }
    } 
    else if(buff[0] == possibleMSOldOffice[0])
    {
        while(buff[iMsgChk] == possibleMSOldOffice[iMsgChk] && iMsgChk < 9)
            iMsgChk++;

        if(iMsgChk >= 8)
        {   
            //old office file format, check 512 offset further in order to filter out real office format
            iMsgChk = 1;
            SetFilePointer(fileHandle, 512, NULL, FILE_BEGIN);
            if(ReadFile(fileHandle, buff, 8, &bytesRead, NULL ) == 0) { return 0; }

            if(buff[0] == msgFormatChkXLSPPT[0])
            {
                while(buff[iMsgChk] == msgFormatChkXLSPPT[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;

                if(iMsgChk == 4)
                    iRet = 2;
            }
            else if(buff[iMsgChk] == msgFormatChkOnlyDOC[iMsgChk])
            {
                while(buff[iMsgChk] == msgFormatChkOnlyDOC[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;
                if(iMsgChk == 4)
                    iRet = 2;

            }
            else if(buff[0] == msgFormatChkOnlyPPT[0])
            {
                while(buff[iMsgChk] == msgFormatChkOnlyPPT[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;

                if(iMsgChk == 4)
                    iRet = 3;
            }
            else if(buff[0] == msgFormatChkOnlyXLS[0])
            {

                while(buff[iMsgChk] == msgFormatChkOnlyXLS[iMsgChk] && iMsgChk < 9)
                    iMsgChk++;

                if(iMsgChk == 9)
                    iRet = 4;
            } 

            if(0 == iRet){
                iRet = 5;
            }
        }
    }


    CloseHandle(fileHandle);

    return iRet;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top