mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-24 10:09:49 +02:00

- try to share some bits between different makefiles, make modifying global compiler flags not such a huge pain. - directly specify we should be using the gold rather than bpf linker - make compiler output largely quiet except where we care - allow warnings to actually be visible - don't delete downloaded tarballs with --really-clean - add missing dependencies between libraries (--no-add-needed/--no-copy-dt-needed-entries causes lots of trouble) - update readme to show what to install to build I made minimal changes to the loader makefile - it breaks easily. -Os prevents if from being able to load libc, for instance
189 lines
4.7 KiB
C
189 lines
4.7 KiB
C
/*!
|
|
* @file unix_socket_server.c
|
|
* @brief Definitions for functions which provide an unix domain socket server.
|
|
* @details An implementation of an unix domain socket for local communications.
|
|
* Useful to communicate data between processes. It is used while in
|
|
* meterpreter migration to share the socket between the old and new
|
|
* host process.
|
|
*/
|
|
#include "unix_socket_server.h"
|
|
|
|
/*!
|
|
* @brief Creates an unix local domain socket and listens on it.
|
|
* @param s Pointer to the \c server_un to start.
|
|
* @param sock_path File path for the local domain socket.
|
|
* @returns Indication of success or failure.
|
|
* @retval 0 Indicates success.
|
|
*/
|
|
LONG
|
|
start_server(server_un *s, LPSTR sock_path) {
|
|
LONG flags;
|
|
|
|
if ((sock_path == NULL) || (s == NULL))
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
s->timeout.tv_sec = DEFAULT_TIMEOUT; // Default timeout
|
|
s->timeout.tv_usec = 0;
|
|
|
|
dprintf("[UNIX SOCKET SERVER] Setting up the server");
|
|
if ((s->socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
dprintf("[UNIX SOCKET SERVER] socket failed");
|
|
return errno;
|
|
}
|
|
|
|
// Set up non blocking mode
|
|
// http://stackoverflow.com/questions/3444729/using-accept-and-select-at-the-same-time
|
|
FD_ZERO(&(s->set));
|
|
FD_SET(s->socket, &(s->set));
|
|
flags = fcntl(s->socket, F_GETFL, 0);
|
|
fcntl(s->socket, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
s->local.sun_family = AF_UNIX;
|
|
|
|
memset(s->local.sun_path, 0, UNIX_PATH_MAX);
|
|
strncpy(s->local.sun_path, sock_path, UNIX_PATH_MAX - 1);
|
|
unlink(s->local.sun_path);
|
|
|
|
if (bind(s->socket, (struct sockaddr *)&(s->local), sizeof(struct sockaddr_un)) == -1) {
|
|
dprintf("[UNIX SOCKET SERVER] bind failed");
|
|
return errno;
|
|
}
|
|
|
|
if (listen(s->socket, 1) == -1) {
|
|
dprintf("[UNIX SOCKET SERVER] listen failed");
|
|
return errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Accepts a new connection.
|
|
* @param s Pointer to the \c server_un listening.
|
|
* @param timeout Time, in seconds, to wait for a new connection (default = 5).
|
|
* @returns Indication of success or failure.
|
|
* @retval 0 Indicates success.
|
|
*/
|
|
LONG
|
|
accept_connection(server_un *s, DWORD timeout) {
|
|
connection_un *c;
|
|
LONG rv;
|
|
int len;
|
|
|
|
if (s == NULL) {
|
|
dprintf("[UNIX SOCKET SERVER] NULL server");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
c = &(s->client);
|
|
|
|
if (c == NULL) {
|
|
dprintf("[UNIX SOCKET SERVER] NULL server");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (timeout != -1) {
|
|
s->timeout.tv_sec = timeout;
|
|
}
|
|
|
|
dprintf("[UNIX SOCKET SERVER] Waiting for a new connection");
|
|
rv = select(s->socket + 1, &(s->set), NULL, NULL, &(s->timeout));
|
|
|
|
if(rv == -1) {
|
|
dprintf("[UNIX SOCKET SERVER] select failed");
|
|
return errno;
|
|
} else if (rv == 0) {
|
|
dprintf("[UNIX SOCKET SERVER] timeout");
|
|
return ETIME;
|
|
}
|
|
|
|
len = sizeof(struct sockaddr_un);
|
|
if ((c->socket = accept(s->socket, (struct sockaddr *)&(c->remote), &len)) == -1) {
|
|
dprintf("[UNIX SOCKET SERVER] accept failed");
|
|
return errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Close an existent connection.
|
|
* @param c Pointer to the \c connection_un to close.
|
|
* @returns Indication of success or failure.
|
|
* @retval 0 Indicates success.
|
|
*/
|
|
LONG
|
|
close_connection(connection_un *c) {
|
|
if (c == NULL) {
|
|
dprintf("[UNIX SOCKET SERVER] NULL connection");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (close(c->socket) == -1){
|
|
dprintf("[UNIX SOCKET SERVER] Close connection failed");
|
|
return errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Stops a listening server.
|
|
* @param c Pointer to the \c server_un to stop.
|
|
* @returns Indication of success or failure.
|
|
* @retval 0 Indicates success.
|
|
*/
|
|
LONG
|
|
stop_server(server_un *s) {
|
|
if (s == NULL) {
|
|
dprintf("[UNIX SOCKET SERVER] NULL server");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
close_connection(&(s->client));
|
|
close(s->socket);
|
|
unlink(s->local.sun_path);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Sends a files descriptor over an existing connection.
|
|
* @param c Pointer to the \c connection_un to send the socket.
|
|
* @param fd file descriptor to send.
|
|
* @returns Indication of success or failure.
|
|
* @retval 0 Indicates success.
|
|
*/
|
|
LONG
|
|
send_socket(connection_un *c, HANDLE fd) {
|
|
struct iovec vector;
|
|
struct msghdr msg;
|
|
struct cmsghdr * cmsg;
|
|
|
|
dprintf("[UNIX SOCKET SERVER] Building message for socket sharing...");
|
|
vector.iov_base = "METERPRETER";
|
|
vector.iov_len = strlen("METERPRETER") + 1;
|
|
|
|
msg.msg_name = NULL;
|
|
msg.msg_namelen = 0;
|
|
msg.msg_iov = &vector;
|
|
msg.msg_iovlen = 1;
|
|
|
|
cmsg = alloca(sizeof(struct cmsghdr) + sizeof(fd));
|
|
cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(fd);
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
|
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
|
|
|
msg.msg_control = cmsg;
|
|
msg.msg_controllen = cmsg->cmsg_len;
|
|
|
|
if (sendmsg(c->socket, &msg, 0) != vector.iov_len) {
|
|
dprintf("[UNIX SOCKET SERVER] sendmsg failed");
|
|
return errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|