Tags: use-after-free kernel linux race-condition 

Rating: 4.5


## Intro

Hi guys, this is the writeup for the challenge _Pwnable01_ from Whitehat Grandprix 06 Final

Please check out [the full writeup at here](https://trungnguyen1909.github.io/blog/post/WhiteHatGrandPrix06/Pwn01/)

You may want to checkout the [exploit code and challenge's source](https://github.com/TrungNguyen1909/writeups/tree/master/WhiteHatGrandPrix06/Pwn01)

## Challenge

> #pwn01:
You can ssh into our server as a low-privilege user. Can you exploit our scull driver and read the flag?

>Note: - You have 12 times to request us to restart your virtual machine (in case your virtual machine crashed).

We are provided a zip file containing a VM image for the challenge and its source code.

### Spot the differences
Noticing the open source license text on top of the source code files, I did a quick search to find the [original source code](https://github.com/jesstess/ldd4/blob/master/scull/main.c), which then could be diffed to find the changes.

#### Differences

The mutex statements were removed, definitely mean there will be some race conditions going on here.

A new function, reachable from `ioctl`, named `scull_shift`.

### Device structure

Each device has a linked list of quantum sets, each set contains a quantum, which is an array of data.

The number of quantum in each set and the size of each quantum is initialized with global variables
extern int scull_quantum;
extern int scull_qset;

These parameters can be get/set using ioctl cmds `SCULL_IOCGQUANTUM`, `SCULL_IOCSQUANTUM`, `SCULL_IOCGQSET`, and `SCULL_IOCSQSET`, respectively.

Each set and its quantums' data are allocated with `kmalloc` in function `scull_write`, called when writing data to the device.

The data could also be read. The function handling that operation is `scull_read`.

`scull_read` and `scull_write` use the current file offset `f_pos` to determine which buffer to read from/write to. Sets are "next to" each others, in each set, quantums are "next to" each other.

### Racy `scull_shift`

This function will go through each set, freeing `n` first quantums, and shift the remaining ones to the front.

However, the process is done while not holding to the lock and freed pointers are left as it until all quantums have been freed, there is time frame starts after the quantums are freed and ends when all quantums are shifted. During the time, read and write operations to the device may be done on the freed buffers, causing a _use-after-free_ bug.

## Exploitation


Please read the remaining of the writeup at [here](https://trungnguyen1909.github.io/blog/post/WhiteHatGrandPrix06/Pwn01/)

Original writeup (https://trungnguyen1909.github.io/blog/post/WhiteHatGrandPrix06/Pwn01/).