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
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.
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.
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 |