7. A closer look

 

It looks worse than you can imagine!

I can imagine some pretty bad things!

That's why I said *worse*!

 Terry Pratchett, Moving Pictures

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

Command: src/entry_point/segments.sh
#!/bin/sh
cd ${TMP}/one_step_closer/e1i1 \
&& ls -l sh_infected \
&& readelf -l sh_infected

Output: out/redhat-linux-i386/entry_point/segments
-rwxr-xr-x    1 alba     anonymou   524060 Jun 30 00:06 sh_infected

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

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4
  INTERP         0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x7a273 0x7a273 R E 0x1000
  LOAD           0x07a280 0x080c2280 0x080c2280 0x057e0 0x09bd0 RW  0x1000
  DYNAMIC        0x07f980 0x080c7980 0x080c7980 0x000e0 0x000e0 RW  0x4
  NOTE           0x000108 0x08048108 0x08048108 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 .rel.got .rel.bss .rel.plt .init .plt .text .fini .rodata 
   03     .data .eh_frame .ctors .dtors .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 = 524060 - 519964 = 4096 = 0x1000

infected.LOAD[1].Filesiz - sh.LOAD[1].Filesiz = 0x7a273 - 0x79273 = 0x1000

infected.LOAD[2].Offset - sh.LOAD[2].Offset = 0x7a280 - 0x79280 = 0x1000

infected.DYNAMIC.Offset - sh.DYNAMIC.Offset = 0x7f980 - 0x7e980 = 0x1000

7.1. First scan

The big output of the scanner from Turn the pages contains the executable from last chapter. But for clarity we repeat the exercise.

Command: src/entry_point/scan_dist.sh
#!/bin/sh
echo	"/bin/bash
	${TMP}/one_step_closer/e1i1/sh_infected" \
| src/scanner/dist.pl

Output: out/redhat-linux-i386/entry_point/scan
tmp/redhat-linux-i386/one_step_closer/e1i1/sh_infected virtaddr=0x080c2280 dist=0x0000000d
   2 files;    1 detected; min=0x0000000d; max=0x0000100d

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

7.2. Looking around

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

entry_point_ofs = 0x8059380 - 0x8048000 = 0x11380 = 70528 bytes.

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

entry_point_ofs = 0x80c1280 - 0x8048000 = 0x79280 = 496256 bytes.

end_of_LOAD1 = 0x8048000 + 0x7a273 = 0x80c2273

entry_point_distance_to_end = 0x80c2273 - 0x80c1280 = 0xff3 = 4083

This is another easy vulnerability to scanners. But the bad news ain't over. readelf(1) features another option, -S.

Command: src/entry_point/sections.sh
#!/bin/sh
ls -l /bin/bash
readelf -S /bin/bash

Output: out/redhat-linux-i386/entry_point/sections
-rwxr-xr-x    1 root     root       519964 Jul  9  2001 /bin/bash
There are 25 section headers, starting at offset 0x7eb34:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        080480f4 0000f4 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048108 000108 000020 00   A  0   0  4
  [ 3] .hash             HASH            08048128 000128 002994 04   A  4   0  4
  [ 4] .dynsym           DYNSYM          0804aabc 002abc 0065c0 10   A  5   1  4
  [ 5] .dynstr           STRTAB          0805107c 00907c 0067db 00   A  0   0  1
  [ 6] .gnu.version      VERSYM          08057858 00f858 000cb8 02   A  4   0  2
  [ 7] .gnu.version_r    VERNEED         08058510 010510 000080 00   A  5   2  4
  [ 8] .rel.got          REL             08058590 010590 000008 08   A  4  14  4
  [ 9] .rel.bss          REL             08058598 010598 000050 08   A  4  17  4
  [10] .rel.plt          REL             080585e8 0105e8 000478 08   A  4   c  4
  [11] .init             PROGBITS        08058a60 010a60 000018 00  AX  0   0  4
  [12] .plt              PROGBITS        08058a78 010a78 000900 04  AX  0   0  4
  [13] .text             PROGBITS        08059380 011380 053cb0 00  AX  0   0 16
  [14] .fini             PROGBITS        080ad030 065030 00001e 00  AX  0   0  4
  [15] .rodata           PROGBITS        080ad060 065060 014213 00   A  0   0 32
  [16] .data             PROGBITS        080c2280 079280 0054a0 00  WA  0   0 32
  [17] .eh_frame         PROGBITS        080c7720 07e720 000004 00  WA  0   0  4
  [18] .ctors            PROGBITS        080c7724 07e724 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        080c772c 07e72c 000008 00  WA  0   0  4
  [20] .got              PROGBITS        080c7734 07e734 00024c 04  WA  0   0  4
  [21] .dynamic          DYNAMIC         080c7980 07e980 0000e0 08  WA  5   0  4
  [22] .sbss             PROGBITS        080c7a60 07ea60 000000 00   W  0   0  1
  [23] .bss              NOBITS          080c7a60 07ea60 0043f0 00  WA  0   0 32
  [24] .shstrtab         STRTAB          00000000 07ea60 0000d4 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

The most interesting entry is .text. The start of the section, 0x8059380, equals the entry point as reported by option -l in Bashful glance.

7.3. Second scan

The following scanner compares the start of section .text with the entry point. It's structure is similar to the script from Turn the pages.

Source: src/scanner/entry_point.pl
#!/usr/bin/perl -w
use strict;

my $min = 0xFFFFFFFF;
my $max = 0;
my $detected = 0;
LOOP: while(my $filename = <>)
{
  chomp $filename; $filename =~ s/^\s*//;
  next LOOP if ( ! -e $filename );
  open(ELF, "readelf -Sl $filename 2>&1 |") || die "$1 ($filename)";

  my $entry_point;
  my $start_of_text;
  while(my $line = <ELF>)
  {
    chomp $line;
    if ($line =~ m/^Entry point 0x([0-9A-Fa-f]+)/)
    {
      $entry_point = hex($1);
    }
    elsif ($line =~ m/^\s*\[[\s\d]+\]\s+.text\s+PROGBITS\s+([0-9A-Fa-f]+)/)
    {
      $start_of_text = hex($1);
    }
  }
  close ELF;
  if (!defined($entry_point))
  {
    printf "%-46s has no entry point.\n", $filename;
  }
  elsif ($entry_point != $start_of_text)
  {
    $detected++;
    printf "%-46s ep=0x%08x sot=0x%08x\n",
      $filename, $entry_point, $start_of_text;
  }
}
printf "%4d files; %4d detected\n", $., $detected;

Once again we first test with typical places like /bin. Everything clean.

Output: out/redhat-linux-i386/scanner/entry_point_big
1475 files;    0 detected

And then with all infected executables. Only a few are detected. Which means there is cure against this vulnerability (just read on).

Output: out/redhat-linux-i386/scanner/entry_point_small
  35 files;    5 detected