opened 05:41PM - 25 Nov 22 UTC
This is raw notes. This will get edited multiple times prior of having a base to… create a wiki page.
The quick way, no-brainer, is to reflash the same downloaded/compiled firmware and keeping settings, as already documented at:
https://osresearch.net/Updating#reflashing-the-same-firmware
Unless flashrom itself was compromised (meaning that the payload is tampered), reflashing the same firmware image using the menu options to flash new firmware while keeping settings will reflash IFD+ME+GBE+coreboot+payload+current CBFS files. Since coreboot measures its bootblock + ramstage+romstage+payload, and then Heads measures added CBFS content, TOTP/HOTP measurements should be the same, and TOTP/HOTP unsealing of secrets should match.
But that doesn't answer the introspection need of some users to actually validate that the firmware components are actually in the expected state. And those notes, even better, if translated into code, should answer those needs.
-----
# Taking an internal backup of the firmware to be inspected externally
From Heads Recovery console, one can easily obtain actual BOARD_NAME and FW_VER that includes the bits we want to differenciate properly the actual board and flashed Heads commit ID in case we want to go back.
From Heads recovery shell, with a USB thumb drive ready to receive backup, we mount usb drive in read+write and we take a backup with proper naming scheme:
```
mount-usb rw
flashrom -p internal -r /media/$CONFIG_BOARD-$(echo $FW_VER|awk -F ' ' '{print $2}'_backup.rom
umount /media
```
# Extracting content from that firmware image for validation
Unfortunately, coreboot-utils are precompiled for a limited number of distributions today. I'll take for granted here that debian12 is installed under QubesOS (see unman's repo https://qubes.3isec.org/Templates_4.1/)
Then a quick `sudo apt install coreboot-utils binwalk` will make the tools available with/without sudo.
Each Heads board's build comes with a hashes.txt file. It is either dowloadable from CircleCI artifacts, or can be seen, and copy pasted from a build's output given on screen.
Following download instructions will lead you to the hashes step of any CircleCI build: https://osresearch.net/Downloading
Now.
After having mounted our USB thumb drive under a debian-12 based qube with tools installed, from command line, having passed the USB thumb drive to our newly booted qube:
```
sudo mount /dev/sda1 /media
mkdir -p /tmp/inspection
cp /media/x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom /tmp/inspection
cd /tmp/inspection
```
And then we work on our copied to memory image.
We can extract partitions not managed from coreboot actual versions measurements:
```
user@heads-backup-extraction:/tmp/inspection$ ifdtool -x x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom
File x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom is 12582912 bytes
Flash Region 0 (Flash Descriptor): 00000000 - 00000fff
Flash Region 1 (BIOS): 0001b000 - 00bfffff
Flash Region 2 (Intel ME): 00003000 - 0001afff
Flash Region 3 (GbE): 00001000 - 00002fff
Flash Region 4 (Platform Data): 00fff000 - 00000fff (unused)
user@heads-backup-extraction:/tmp/inspection$ ls -al
total 24592
drwxr-xr-x 3 user user 4096 Nov 25 10:56 .
drwxrwxrwt 12 root root 4096 Nov 25 11:22 ..
-rw-r--r-- 1 user user 4096 Nov 25 12:05 flashregion_0_flashdescriptor.bin
-rw-r--r-- 1 user user 12472320 Nov 25 12:05 flashregion_1_bios.bin
-rw-r--r-- 1 user user 98304 Nov 25 12:05 flashregion_2_intel_me.bin
-rw-r--r-- 1 user user 8192 Nov 25 12:05 flashregion_3_gbe.bin
-rw-r--r-- 1 user user 12582912 Nov 25 10:14 x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom
```
Here one could compare ME against what is downloaded and extracted from Heads scripts, GBE and IFD configs against what is stored under Heads tree.
But most questions are related to the firmware integrity itself, Heads itself:
```
user@heads-backup-extraction:/tmp/inspection$ cbfstool x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom print
FMAP REGION: COREBOOT
Name Offset Type Size Comp
cbfs master header 0x0 cbfs header 32 none
fallback/romstage 0x80 (unknown) 85100 none
cpu_microcode_blob.bin 0x14d80 microcode 26624 none
fallback/ramstage 0x1b600 (unknown) 97676 none
config 0x33400 raw 834 none
revision 0x33780 raw 691 none
fallback/dsdt.aml 0x33a80 raw 14615 none
vbt.bin 0x37400 raw 1433 LZMA (4281 decompressed)
cmos_layout.bin 0x37a00 cmos_layout 1884 none
fallback/postcar 0x381c0 (unknown) 25816 none
fallback/payload 0x3e700 simple elf 7320519 none
heads/initrd/.gnupg/pubring.kbx 0x739b00 raw 11549 none
heads/initrd/.gnupg/trustdb.gpg 0x73c880 raw 1320 none
heads/initrd/etc/config.user 0x73ce00 raw 22 none
(empty) 0x73ce80 null 4337432 none
bootblock 0xb5fdc0 bootblock 65536 none
```
Here again, a lot of stuff there.
# Get build hashes for current rom
x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom is commit 139ecb8
We go over https://github.com/osresearch/heads/commit/139ecb8
We click grewn mark, follow the rabbit to the build for x230-hot-maximized at https://app.circleci.com/jobs/github/osresearch/heads/5448, click the "Output hashes" if this is an old build without artifacts, and copy the output of the hashes there to a local hashes.txt file we make sure to have available for our situation. We can directly save the output from CircleCI's Download Icon, which in our case leads to https://circleci.com/api/v1.1/project/github/osresearch/heads/5448/output/104/0?file=true&allocation-id=63751e76e6fb893f12bf3473-0-build%2F97AF006
From now on I consider we have that file saved into hashes.txt to be used locally.
# Extract content from coreboot's payload
```
user@heads-backup-extraction:/tmp/inspection$ mkdir -p payload_content
user@heads-backup-extraction:/tmp/inspection$ cbfstool x230-hotp-maximized-Heads-v0.2.0-1296-g139ecb8_backup.rom extract -n fallback/payload -f payload_content/payload -m x86
```
We now have coreboot's payload.
```
user@heads-backup-extraction:/tmp/inspection/payload_content$ ls -al
total 7180
drwxr-xr-x 2 user user 4096 Nov 25 12:22 .
drwxr-xr-x 3 user user 4096 Nov 25 10:56 ..
-rw-r--r-- 1 user user 11525 Nov 25 10:58 hashes.txt
-rw-r--r-- 1 user user 7328543 Nov 25 12:14 payload
```
We extract the content with binwalk
```
user@heads-backup-extraction:/tmp/inspection/payload_content$ binwalk --extract payload
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 ELF, 32-bit LSB executable, Intel 80386, version 1 (SYSV)
13013 0x32D5 xz compressed data
2072933 0x1FA165 MySQL MISAM compressed data file Version 8
2910340 0x2C6884 bix header, header size: 64 bytes, header CRC: 0xE802F8, created: 2106-02-07 01:21:09, image size: 186 bytes, Data Address: 0x1000000, Entry Point: 0x83BB9000, data CRC: 0x50F, compression type: none, image name: ""
2923392 0x2C9B80 xz compressed data
3035935 0x2E531F xz compressed data
user@heads-backup-extraction:/tmp/inspection/payload_content$ ls -al
total 7184
drwxr-xr-x 3 user user 4096 Nov 25 12:22 .
drwxr-xr-x 3 user user 4096 Nov 25 10:56 ..
-rw-r--r-- 1 user user 11525 Nov 25 10:58 hashes.txt
-rw-r--r-- 1 user user 7328543 Nov 25 12:14 payload
drwxr-xr-x 2 user user 4096 Nov 25 12:22 _payload.extracted
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ ls | while read file; do sha256sum $file; done | while read line; do hash=$(echo $line | awk -F " " '{print $1}'); file=$(echo $line | awk -F " " '{print $2}'); grep $hash ../hashes.txt && echo "we have match for $hash in $file"; done
b3387d6b04c6246198638a46a2fec5bb7623a99a97189a26c5e019524aef8992 build/x86/x230-hotp-maximized/initrd.cpio.xz
we have match for b3387d6b04c6246198638a46a2fec5bb7623a99a97189a26c5e019524aef8992 in 2E531F.xz
```
So we have a matching initrd.cpio.xz into 2E531F.xz
We could dig more into that, and will (after all, everything hashes.txt is detailing why we have a match for the payload).
# hashes.txt can be used under recovery shell to verify hashes of the initrd binaries
The paths undr hashes.txt are relative. If we have hashes.txt under USB thumb drive, from Heads recovery shell:
cd /
mount-usb
sha256sum -c /media/hashes.txt
Will give OK reports for all files that were found, including libraries and binaries and scripts user by heads, as seen under
# Check bzImage
Unfortunately, this requires CircleCI bzImage since mathing can only be made against decompressed binary.
After our binwalk --extract command:
```
user@heads-backup-extraction:/tmp/inspection/payload_content$ cd _payload.extracted/
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ ls
2C9B80.xz 2E531F 2E531F.xz 32D5 32D5.xz
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ wget -O extract-vmlinux https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-vmlinux
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ chmod +x ./extract-vmlinux
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ ls -al
total 47316
drwxr-xr-x 2 user user 4096 Nov 25 12:34 .
drwxr-xr-x 3 user user 4096 Nov 25 12:22 ..
-rw-r--r-- 1 user user 4405151 Nov 25 12:22 2C9B80.xz
-rw-r--r-- 1 user user 12882944 Nov 25 12:22 2E531F
-rw-r--r-- 1 user user 4292608 Nov 25 12:22 2E531F.xz
-rw-r--r-- 1 user user 19528104 Nov 25 12:22 32D5
-rw-r--r-- 1 user user 7315530 Nov 25 12:22 32D5.xz
-rwxr-xr-x 1 user user 1695 Nov 25 12:34 extract-vmlinux
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ ./extract-vmlinux 32D5 > vmlinux_local
```
Download bzImage from CircleCI artifact
```
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ ./extract-vmlinux bzImage > vmlinux_remote
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$ diff vmlinux_local vmlinux_remote
user@heads-backup-extraction:/tmp/inspection/payload_content/_payload.extracted$
```