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/i386-redhat-linux/entry_point/segments
-rwxrwxr-x 1 alba alba 545192 Aug 16 00:13 sh_infected
Elf file type is EXEC (Executable file)
Entry point 0x80c6420
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 0x7f414 0x7f414 R E 0x1000
LOAD 0x07f420 0x080c7420 0x080c7420 0x05934 0x09ad0 RW 0x1000
DYNAMIC 0x084a0c 0x080cca0c 0x080cca0c 0x000d8 0x000d8 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.dyn .rel.plt .init .plt .text .fini .rodata
03 .data .eh_frame .dynamic .ctors .dtors .got .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 = 545192 - 541096 = 4096 = 0x1000
infected.LOAD[1].Filesiz - sh.LOAD[1].Filesiz = 0x7f414 - 0x7e414 = 0x1000
infected.LOAD[2].Offset - sh.LOAD[2].Offset = 0x7f420 - 0x7e420 = 0x1000
infected.DYNAMIC.Offset - sh.DYNAMIC.Offset = 0x84a0c - 0x83a0c = 0x1000
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/i386-redhat-linux/entry_point/scan
tmp/i386-redhat-linux/one_step_closer/e1i1/sh_infected virtaddr=0x080c7420 dist=0x0000000c
2 files; 1 detected; min=0x0000000c; max=0x0000100c |
This is like playing chess against oneself, and losing. Can't do much about it, though.
The value of Entry point changed dramatically. In the original it is in the first part of the file:
entry_point_ofs = 0x8059440 - 0x8048000 = 0x11440 = 70720 bytes.
The infected copy moved that to less than 4096 bytes from the end of the code segment.
entry_point_ofs = 0x80c6420 - 0x8048000 = 0x7e420 = 517152 bytes.
end_of_LOAD1 = 0x8048000 + 0x7f414 = 0x80c7414
entry_point_distance_to_end = 0x80c7414 - 0x80c6420 = 0xff4 = 4084
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/i386-redhat-linux/entry_point/sections
-rwxr-xr-x 1 root root 541096 Apr 12 18:09 /bin/bash
There are 23 section headers, starting at offset 0x83e10:
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 002a20 04 A 4 0 4
[ 4] .dynsym DYNSYM 0804ab48 002b48 0067f0 10 A 5 1 4
[ 5] .dynstr STRTAB 08051338 009338 006538 00 A 0 0 1
[ 6] .gnu.version VERSYM 08057870 00f870 000cfe 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08058570 010570 000070 00 A 5 2 4
[ 8] .rel.dyn REL 080585e0 0105e0 000058 08 A 4 0 4
[ 9] .rel.plt REL 08058638 010638 0004a0 08 A 4 b 4
[10] .init PROGBITS 08058ad8 010ad8 000018 00 AX 0 0 4
[11] .plt PROGBITS 08058af0 010af0 000950 04 AX 0 0 4
[12] .text PROGBITS 08059440 011440 058680 00 AX 0 0 16
[13] .fini PROGBITS 080b1ac0 069ac0 00001e 00 AX 0 0 4
[14] .rodata PROGBITS 080b1ae0 069ae0 014934 00 A 0 0 32
[15] .data PROGBITS 080c7420 07e420 0055e8 00 WA 0 0 32
[16] .eh_frame PROGBITS 080cca08 083a08 000004 00 WA 0 0 4
[17] .dynamic DYNAMIC 080cca0c 083a0c 0000d8 08 WA 5 0 4
[18] .ctors PROGBITS 080ccae4 083ae4 000008 00 WA 0 0 4
[19] .dtors PROGBITS 080ccaec 083aec 000008 00 WA 0 0 4
[20] .got PROGBITS 080ccaf4 083af4 000260 04 WA 0 0 4
[21] .bss NOBITS 080ccd60 083d60 004190 00 WA 0 0 32
[22] .shstrtab STRTAB 00000000 083d60 0000b0 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, 0x8059440, equals the entry point as reported by option -l in Bashful glance.
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 $readelf = $ENV{'READELF'}
|| die "Environment variable READELF undefined.";
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/i386-redhat-linux/scanner/entry_point_big
1543 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/i386-redhat-linux/scanner/entry_point_small
one_step_closer/e1i1/tcsh_infected ep=0x0808af70 sot=0x0804a1f0
one_step_closer/e1i1/perl_infected ep=0x080f2260 sot=0x08059b20
one_step_closer/e1i1/which_infected ep=0x0804b2c0 sot=0x08048b30
one_step_closer/e1i1/sh_infected ep=0x080c6420 sot=0x08059440
one_step_closer/e1i1/strip_sh_infected ep=0x080c6420 sot=0x08059440
35 files; 5 detected |