Installing cuttlefish
sudo apt install -y git devscripts equivs config-package-dev debhelper-compat golang curl
git clone https://github.com/google/android-cuttlefish
cd android-cuttlefish
tools/buildutils/build_packages.sh
sudo dpkg -i ./cuttlefish-base_*_*64.deb || sudo apt-get install -f
sudo dpkg -i ./cuttlefish-user_*_*64.deb || sudo apt-get install -f
sudo usermod -aG kvm,cvdnetwork,render $USER
sudo reboot
Installation of libinfo5 for ubuntu 24.04 if its needed
sudo apt update
wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb
sudo apt install ./libtinfo5_6.3-2ubuntu0.1_amd64.deb
Android kernel compilation
mkdir kernel && cd kernel
repo init -u https://android.googlesource.com/kernel/manifest -b \
common-android-mainline // or common-android14-5.15
repo sync -j
tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist
After the copilation of cuttlefish we need to download artifacts
http://ci.android.com/
Download the latest build
aosp_cf_x86_64_phone-img-xxxxxx.zip
cvd-host_package.tar.gz
Under the aosp_cf_x86_64_phone Extract it as this guide says
https://source.android.com/docs/devices/cuttlefish/get-started
cvd create \
-kernel_path=./out/virtual_device_x86_64/dist/bzImage \
-initramfs_path=./out/virtual_device_x86_64/dist/initramfs.img
This is the run.sh's content
HOME=$PWD cvd create \
-kernel_path=/home/asd/Documents/pixel6/aosp_cf_x86_64_phone-img-13243112/cvd-host_package/bzImage \
-initramfs_path=/home/asd/Documents/pixel6/aosp_cf_x86_64_phone-img-13243112/cvd-host_package/initramfs.img
I added a kernel driver to the
./common/drivers/hello/hello_timer.c
./common/drivers/hello/Makefile
./common/drivers/hello/Kconfig
hello_timer.c (Prints hello world every 1 sec to the dmesg so we can check if its loaded or not)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#define TIMER_INTERVAL 1 // 1 second
static struct timer_list my_timer;
// Timer callback function
static void timer_callback(struct timer_list *timer)
{
printk(KERN_INFO "Hello, World!\n");
// Re-arm the timer
mod_timer(&my_timer, jiffies + HZ * TIMER_INTERVAL);
}
static int __init hello_init(void)
{
printk(KERN_INFO "Loading Hello World Timer Module...\n");
// Initialize and start the timer
timer_setup(&my_timer, timer_callback, 0);
mod_timer(&my_timer, jiffies + HZ * TIMER_INTERVAL);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Unloading Hello World Timer Module...\n");
// Delete the timer
del_timer(&my_timer);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Test User");
MODULE_DESCRIPTION("Kernel module that prints Hello, World! every second.");
MODULE_VERSION("1.0");
module_init(hello_init);
module_exit(hello_exit);
Makefile:
obj-m += hello_timer.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Kconfig:
menuconfig HELLO_TIMER
tristate "Hello World Timer Module"
help
This is a simple kernel module that prints "Hello, World!" every second.
if HELLO_TIMER
config HELLO_TIMER_DEBUG
bool "Enable debug messages"
default n
help
Enable additional debug messages in the Hello Timer module.
endif
In the /common/drivers i modified 2 files Kconfig and Makefile Kconfig:
source "drivers/hello/Kconfig"
Makefile:
obj-y += hello/
and build again
tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist
If the build fails dont worry find the hello_timer.ko by
find . -name hello_timer.ko
and
adb push /location/of/the/hello_timer.ko /data/local/tmp
adb root
adb shell
cd /data/local/tmp
insmod hello_timer.ko
Now we are going to put our vullnerable driver to the android kernel and compile again it will fail and we take the vuln.ko and insmod, simple
if anyone of you suceeded to the integrating the kernel driver to the kernel i would really appreciate to see your pull request ,
Our vulnerable kernel module
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#define DEVICE_NAME "uaf_device"
#define IOCTL_MAGIC 'U'
// IOCTL Commands
#define IOCTL_ALLOC_MEM _IO(IOCTL_MAGIC, 0)
#define IOCTL_FREE_MEM _IO(IOCTL_MAGIC, 1)
#define IOCTL_READ_MEM _IOR(IOCTL_MAGIC, 2, char *)
#define IOCTL_WRITE_MEM _IOW(IOCTL_MAGIC, 3, char *)
static int major_num = 100; // Set the major number to 100
static char *buffer = NULL;
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case IOCTL_ALLOC_MEM:
pr_info("Allocating memory for device\n");
buffer = kmalloc(128, GFP_KERNEL);
if (!buffer) {
pr_err("Memory allocation failed\n");
return -ENOMEM;
}
memset(buffer, 0, 128);
pr_info("Memory allocated at %p\n", buffer);
break;
case IOCTL_FREE_MEM:
pr_info("Freeing memory\n");
if (buffer) {
kfree(buffer);
pr_info("Memory freed\n");
} else {
pr_err("Memory not allocated yet\n");
}
break;
case IOCTL_READ_MEM:
pr_info("Reading memory\n");
if (buffer) {
if (copy_to_user((char *)arg, buffer, 128)) {
return -EFAULT;
}
} else {
pr_err("Memory not allocated\n");
return -EFAULT;
}
break;
case IOCTL_WRITE_MEM:
pr_info("Writing to memory\n");
if (buffer) {
if (copy_from_user(buffer, (char *)arg, 128)) {
return -EFAULT;
}
pr_info("Memory written: %s\n", buffer);
} else {
pr_err("Memory not allocated\n");
return -EFAULT;
}
break;
default:
pr_err("Invalid ioctl command\n");
return -EINVAL;
}
return 0;
}
static int device_open(struct inode *inode, struct file *file)
{
pr_info("Device opened\n");
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
pr_info("Device closed\n");
return 0;
}
static struct file_operations fops = {
.open = device_open,
.release = device_release,
.unlocked_ioctl = device_ioctl,
};
static int __init uaf_driver_init(void)
{
int ret;
// Register the device with major number 100
ret = register_chrdev(major_num, DEVICE_NAME, &fops);
if (ret < 0) {
pr_err("Failed to register device with major number %d\n", major_num);
return ret;
}
pr_info("UAF driver registered with major number %d\n", major_num);
return 0;
}
static void __exit uaf_driver_exit(void)
{
if (buffer) {
kfree(buffer);
}
unregister_chrdev(major_num, DEVICE_NAME);
pr_info("UAF driver unregistered\n");
}
module_init(uaf_driver_init);
module_exit(uaf_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple UAF driver with IOCTLs and write to memory");
after insmod we need to mknod to see under the /dev folder
mknod /dev/uaf_device c 100 0
Yo ucan undo the adb root by
adb unroot
You can see that the driver is accessible now,
vsoc_x86_64:/ $ ls /dev/uaf_device
/dev/uaf_device
vsoc_x86_64:/ $
Change the context of the uaf_device because SELinux blocks the access to the driver Binder context is suitable for the use
adb root
adb shell
chcon u:object_r:binder_device:s0 /dev/uaf_device
chown shell:shell /dev/uaf_device
adb unroot
adb shell
cd /data/local/tmp
./uaf
vsoc_x86_64:/data/local/tmp $ ./uaf
[+] Opened device /dev/uaf_device
[+] Wrote data to device: UAF Test Data
[+] Closed device, buffer should be freed now
[+] Reopened device
[+] Read from device after free: Test data in the kernel buffer
vsoc_x86_64:/data/local/tmp $
Now we have 100byte uaf
Firstly we need to find out that where the allocated object stays in the slab caches We simple spay and allocate many uaf object and see which slab cache is getting bigger.
cat /proc/slabinfo
Spray code
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEVICE_PATH "/dev/uaf_device"
// IOCTL Commands
#define IOCTL_MAGIC 'U'
#define IOCTL_ALLOC_MEM _IO(IOCTL_MAGIC, 0)
#define IOCTL_FREE_MEM _IO(IOCTL_MAGIC, 1)
#define IOCTL_READ_MEM _IOR(IOCTL_MAGIC, 2, char *)
#define IOCTL_WRITE_MEM _IOW(IOCTL_MAGIC, 3, char *)
int main() {
int fd = open(DEVICE_PATH, O_RDWR);
if (fd < 0) {
perror("Failed to open device");
return -1;
}
for(int i = 0; i < 1000000; i++) {
// Execute IOCTL Command 1
ioctl(fd, IOCTL_ALLOC_MEM);
}
return 0;
}
As we can see that spraying vulnerable object is allocated in kmalloc-128 Because the uaf object is < 128 and > 64
In order to make the process easy if you get crash of your emulator create config.sh with the content as following.
adb root
adb shell insmod /data/local/tmp/hello_timer.ko
adb shell mknod /dev/uaf_device c 100 0
adb shell setenforce 0
adb shell chcon u:object_r:system_app:s0 /dev/uaf_device
adb shell setenforce 1
adb shell chown shell:shell /dev/uaf_device
adb unroot
Eventhough alot of attempts are made for to getting the right permission i couldnt succedded so that i will disable SELinux to continue to playing around. :(
adb root
setenforce 0
adb unroot


