Skip to content

Commit

Permalink
Add Google 2020 Root Power writeup
Browse files Browse the repository at this point in the history
  • Loading branch information
nankeen committed Aug 25, 2020
1 parent c92312c commit 1b9929f
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 0 deletions.
175 changes: 175 additions & 0 deletions _posts/2020-08-25-googlectf-2020-root-power.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
title: "Google CTF Qualifiers 2020: Root Power"
date: 2020-08-25
categories: [writeup]
tags: ["ctf", "rev"]
authors: [nankeen]
---

This weekend, cr0wn competed in [Google CTF 2020](https://ctftime.org/event/1041). We placed 16th, qualifying for the next stage.

We were provided with a virtual machine disk image and had to recover the ___root password___.

## Outline

1. First look at disk image.
2. Access the filesystem.
3. Discover the authentication mechanism.
4. Reverse engineering a kernel module.
5. Discovering what `initramfs` contains and does.
6. Reverse engineering an AML file.
7. Win.

## Tl;dr

The given image has a pluggable authentication module that checks if a char device `/dev/chck` reads __1__ when __root__ login is attempted.
The kernel module responsible for said device reads from ACPI, logic of which is within a ACPI Machine Language (AML) file.
Decompiling it shows that it is a PS/2 keyboard device, and the make/break codes form the flag.

## First look

The archive contains a disk image and a script to run it in QEMU.
GRUB menu reveals that it is Arch Linux, and you are greeted with a login prompt.


![Grub Menu](/images/google20/root-power/qemu-1.png "Grub Menu")
![Login Prompt](/images/google20/root-power/qemu-2.png "Login Prompt")

Binwalk suggests there's a EXT filesystem at offset `0x100000`.

![Binwalk](/images/google20/root-power/binwalk.png "Binwalk")

## The filesystem

The filesystem can be mounted with:

```bash
mkdir -p mnt && sudo mount -o loop,offset=1048576 disk.img mnt
```

My first instinct was to check `/etc/shadow` and the boot files, the former was a rabbit hole.
I also checked `initramfs` to see if there are any files I might've missed, it contains `ssdt.aml`, we'll come back to this later.

## Authentication mechanism
A feature that authenticated users in Linux was PAM.
So I checked out the modules in `/etc/pam.d/system-auth`, and `pam_chck.so` was mentioned.

`pam_chck.so` looks for the __root__ user, then returns 0 (success) if `check_device() == 1`.

```c
ulong pam_sm_authenticate(undefined8 param_1)
{
int r;
ulong ret;
char *user;
uint _r;

_r = pam_get_user(param_1,&user,"Username: ",&user);
if (_r == 0) {
r = strcmp(user,"root");
if (r == 0) {
fwrite("Password: ",1,10,stderr);
r = check_device();
if (r == 1) {
fprintf(stderr,"\n\nWelcome %s\n",user);
ret = 0;
}
else {
fwrite("Wrong username or password",1,0x1a,stderr);
ret = 6;
}
}
else {
ret = 6;
}
}
else {
ret = (ulong)_r;
}
return ret;
}
```
`check_device()` is a simple function that reads 2 bytes from `/dev/chck` and returns the result as an integer.
```c
int check_device(void)
{
int ret;
char buf [2];
FILE *fd;
fd = fopen("/dev/chck","r");
fgets(buf,2,fd);
fclose(fd);
ret = atoi(buf);
return ret;
}
```

What exactly provides this device?


## Chck kernel module

Devices in `/dev/` are usually added through kernel modules, so I looked for `.ko` files in the image.
Immediately, `chck.ko` jumped out so it was given the decompiler treatment, indeed it handles `/dev/chck`.

```c
undefined8 chck_read(undefined8 param_1,undefined8 param_2,undefined8 param_3,undefined8 param_4)
{
int chck_r;
undefined8 r;
undefined8 extraout_RDX;
long in_GS_OFFSET;
undefined8 acpi_data;
char local_22 [2];
long canary;

__fentry__();
canary = *(long *)(in_GS_OFFSET + 0x28);
chck_r = acpi_evaluate_integer(chck_handle,"CHCK",0,&acpi_data);
if (chck_r == 0) {
snprintf(local_22,2,"%llu",acpi_data);
r = simple_read_from_buffer(param_2,extraout_RDX,param_4,local_22,2);
}
else {
printk("\x014Chck: cannot read from method CHCK");
r = 0xffffffffffffffff;
}
if (canary == *(long *)(in_GS_OFFSET + 0x28)) {
return r;
}
// WARNING: Subroutine does not return
__stack_chk_fail();
}
```
This function relays reads on `/dev/chck` to ACPI's _CHCK_ device.
My guess was that this was handled early in the boot process --- `initramfs`.
## AML file
`initramfs` contains `ssdt.aml` which can be decompiled with `iasl`, producing ssdt.dsl.
The following helped me make sense of what is happening:
1. https://uefi.org/specifications
2. https://wiki.osdev.org/AML
Here's roughly what it does:
* It defines a device: `CHCK` with 2 operation regions at `SystemIO` addresses `0x60` and `0x64`.
* There's a method, also called `CHCK`, that compares a buffer `KBDB` with `KBDA`, returning 1 if they match and 0 otherwise.
* `KBDB` is populated from `SystemIO:0x60`.
* `KBDA` contained a bunch of pre-defined bytes.
What kind of device is this? Googling ___acpi 0x60 0x64___ yields [this page](https://wiki.osdev.org/%228042%22_PS/2_Controller).
So I made the assumption that `KBDA` contained __PS/2 scan codes__.
That assumption was confirmed with [this table](http://www.vetra.com/scancodes.html).
Each byte represents a make/break code, indicating a keydown/keyup event.
The decode script is trivial and is left as an exercise for the reader.
_Lol kidding_, I did it by hand.
Result was the flag: `CTF{acpi_machine_language}`
Binary file added images/google20/root-power/binwalk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/google20/root-power/qemu-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/google20/root-power/qemu-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1b9929f

Please sign in to comment.