36th Chaos Communication Congress
A peek of 36c3 with my notes
December 28, 2019
I’m at CCC for the first time this year ! Here my notes for a few of the talks.
In an ideal world, one could pick the programming language of their choice and always generate the optimal machine code. But we live in the real world, and it isn't yet possible. Running code in a constrained environment, like baremetal SoCs means that your choice of languages is reduced, and towards low-level languages like C, which come with their own issues. The motivation for Tamago is to be able to run a higher-level language like Go on baremetal.
The goal of the Tamago project is to run Go on baremetal ARMv7, for example to be able to write security-sensitive bootloaders (firmware) on an NXP i.MX6ULL based usbarmory.
This isn't really a new idea, as Unikernels or library OSes often match the same description. But unikernels didn't match the requirements of depending on no C code (not importing another OS or library), or running on small embedded systems, not the cloud.
Go was chosen here because it's relatively easier to learn than other proven-on-embedded languages like Rust. Currently, Tamago is a patched Go compiler that adds another OS support
GOOS=tamago, to be able to run
GOARCH=arm on baremetal. The scope is different from TinyGo, that targets micro-controllers instead, and uses a completely different compiler implementation, as well as not supporting the full runtime and Go language yet. It's also different from the recently announced Embedded Go that targets Thumb and bigger microcontrollers.
The goal of Tamago is to be upstream-able in Go. The current patchset is about 3000 lines of code. That's about ~300 lines of glue code, ~2700 lines of re-used code, like the
plan9 memory allocator or locking from
js,wasm. Then there's ~600 lines of new code to provide ARMv7 and heap init functions.
There are few functions that should be provided in a board-support package: how to get random data, init hw, print a byte on the console, what is the ram size and offset, and how to get high-res time.
Writing drivers in go can be done easily either using Go's assembly support or using unsafe; it also means that the sensitive parts are identified and can be written with care and audited if needed. In the runtime, the only syscall that is implemented is write(), and it is used for debugging on the serial port.
In order to write a baremetal Go program, one should import the board package library to get its side-effects.
The Tamago authors wrote i.MX6 drivers to test their model: for the DCP co-processor, the HW random generator, a USB driver and a USB networking card (CDC-ACM).
Boot2root: Auditing bootloaders by example
Bootloaders are a critical part of any secure boot chain. The authors of this talk had a look at common open source bootloaders to look for any issue they could fine.
They looked at u-boot, a very commonly used bootloader in embedded systems, Coreboot is targeted at modern OSes and used in Chromebooks, Grub used in most Linux distros, Broadcom CFE, iPXE for network boot, Tianocore etc.
In most opensource bootloaders, there is no privilege separation: all codes runs with maximum privileges. The attack surfaces are NVRAM, files and file systems, busses (I2C/SPI…), etc.
For NVRAM, where environment variables are stored, one should look at where the variables are read, and if there's any kind of sanitization. For u-boot, many places were found where env_get() is called without any sort of size check of the data read. The attack scenario is a device for which NVRAM is modifiable (through hardware or host OS); this is then open for exploitation, for which a demo was shown with u-boot.
For the filesystems attack surface, often the images are read on a filesystem that is not signed or integrity checked. An example was given with grub's ext2 symlink handling.
When looking at TCP/IP, many issues can be found: TLV parsing is tricky for example. DNS can be poisoned, DHCP leases can be stolen. In u-boot, the DNS TID is hardcoded to 1, enabling easy mitm. In broadcom CFE, many memory corruptions were found in DHCP, ICMP handling, IP header length etc.
In iPXE for 802.11, a memory corruption bug was found SSID handling. Bluetooth was attacked, and issues were found in proprietary bootloaders. The most interesting attack vectors were in large frame handling and fragmentation, but no example was shown because of NDAs.
USB is also a big attack surface when booting from storage or ethernet dongles. Often, descriptor parsing is wrong, with overflows or double fetches causing TOCTOU issues. In Grub, Tianocore and Seabios, memory corruptions and double fetches issues were found. Recent similar issues in proprietary devices include the Nintendo Switch bootloader issue and iPhone checkm8.
Another attack surface are SMM, for which many problems were found with UEFI Tianocore in the last 15 years. A recent issue was found in Coreboot, for which the range checks were simply not implemented yet.
If DMA is an attack surface (rogue device), IOMMUs are an absolute minimum to defend against the attacks. But then you should make sure that any data you get from a device is properly checked, so old driver code needs to be rewritten and audited. There might also be HW bugs in IOMMUs, sidechannels, data leaks, etc. In edkII (Tianocore), the spec mandates shutting down the IOMMU before chainloading to an OS, so it opens a huge window during which a rogue device can do attacks.
The next attack surfaces are glitching, which means injecting faults in the hardware clocks, voltage sources, or via lasers or EMIs. These hardware side channels are used to extract secrets. Some companies (Chipsec…) also provide optical ROM code extraction by decapping chips.
In conclusion, there's a surprising amount of low quality code in bootloaders (closed and open); and one often encounters NDA walls when looking at proprietary code. The advice is to minimize the image, and turn most extra features off. Enable basic exploit mitigations when compiling. In all of this, Tianocore is well ahead of the game.
The authors called the audience for action in reviewing, fuzzing, and analysing bootloaders.
That's it for 36C3 ! Most talks were recorded with videos already available.