Reverse engineering level with library re-usage.
| Option | Setting |
|---|---|
| Vulnerability Type | Stack |
| Position Independent Executable | Yes |
| Read only relocations | No |
| Non-Executable stack | Yes |
| Non-Executable heap | Yes |
| Address Space Layout Randomisation | Yes |
| Source Fortification | Yes |
#include "../common/common.c" #include <pth.h> #include <openssl/rsa.h> #include "utlist.h" struct ops { void (*register_cmd)(unsigned int opcode, unsigned int flags, void *(*fp)(void *)); void (*unregister_cmd)(unsigned int opcode); }; int parse_pak(unsigned char *pakaddr, size_t paklen, size_t base, struct ops *ops); #define DB (572) int udp; struct pa { unsigned char *buf; ssize_t len; struct sockaddr_in sin; unsigned char *p; ssize_t remainder; }; void free_pa(struct pa *pa) { if(! pa) return; if(! pa->buf) { memset(pa->buf, 0, pa->len); free(pa->buf); } memset(pa, 0, sizeof(struct pa)); free(pa); } typedef struct cmdtab { unsigned int opcode; unsigned int flags; void *(* fp)(void *); struct cmdtab *prev, *next; } cmdtab; cmdtab *cmdtab_head; void *dispatch(void *arg) { struct pa *p = (struct pa *)(arg); int *ip; cmdtab *c = NULL; if(p->len < sizeof(int)) goto bail; ip = (int *)(p->buf); p->p = p->buf + 4; p->remainder = p->len - 4; DL_FOREACH(cmdtab_head, c) { if(c->opcode == ip[0]) { c->fp(p); break; } } bail: free_pa(p); return NULL; } void register_cmd(unsigned int opcode, unsigned int flags, void *(*fp)(void *)) { cmdtab *c; c = calloc(1, sizeof(cmdtab)); c->opcode = opcode; c->flags = flags; c->fp = fp; DL_APPEND(cmdtab_head, c); } void unregister_cmd(unsigned int opcode) { cmdtab *c, *tmp; DL_FOREACH_SAFE(cmdtab_head, c, tmp) { if(c->opcode == opcode) { DL_DELETE(cmdtab_head, c); } } } struct ops regops = { .register_cmd = register_cmd, .unregister_cmd = unregister_cmd }; #define PAKFILE "/opt/fusion/res/level07.pak" void load_and_parse_default_pak() { void *m; int fd; struct stat statbuf; int status; unsigned int base; fd = open(PAKFILE, O_RDONLY); if(! fd) err(1, "Unable to open %s", PAKFILE); if(fstat(fd, &statbuf) == -1) err(1, "Unable to fstat %s", PAKFILE); m = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(m == MAP_FAILED) err(1, "Unable to mmap %s", PAKFILE); // printf("got %d bytes to process\n", statbuf.st_size); status = parse_pak(m, statbuf.st_size, 0, ®ops); // printf("parse_pak result: %08x\n", status); } int download_pak_file(char *host, char *port, unsigned char *key, unsigned char **pakfile, size_t *pakfile_len) { struct sockaddr_in sin; size_t blue; int ret; size_t alloc; int status; int keyidx; int keylen; int i; int fd; status = -1; keylen = strlen(key); keyidx = 0; memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_addr.s_addr = inet_addr(host); sin.sin_port = htons(atoi(port)); sin.sin_family = AF_INET; *pakfile = NULL; *pakfile_len = 0; fd = socket(AF_INET, SOCK_STREAM, 0); if(fd == -1) return; if(pth_connect(fd, (void *)(&sin), sizeof(struct sockaddr_in)) == -1) goto closefd; if(pth_read(fd, &alloc, sizeof(alloc)) != sizeof(alloc)) goto closefd; blue = 0; *pakfile = calloc(alloc, 1); if(*pakfile == NULL) goto closefd; *pakfile_len = alloc; while(alloc - blue) { ret = pth_read(fd, (*pakfile) + blue, alloc - blue); if(ret == -1) goto freemem; if(ret == 0) goto freemem; for(i = 0; i < ret; i++) { //printf("key byte is %02x/%c\n", key[keyidx], key[keyidx]); (*pakfile)[blue + i] ^= key[keyidx]; keyidx = (keyidx + 1) % keylen; } blue += ret; } status = 0; goto closefd; freemem: free(*pakfile); *pakfile = NULL; *pakfile_len = 0; closefd: close(fd); return status; } void *load_new_pakfile(void *arg) { struct pa *p = (struct pa *)(arg); unsigned char *q; unsigned char *host, *port, *key = NULL; unsigned char *pakfile; size_t pakfile_len; host = p->p; q = strchr(p->p, '|'); if(! q) return NULL; *q++ = 0; port = q; q = strchr(q, '|'); if(! q) return NULL; *q++; key = q; if(strlen(key) < 8) return NULL; // printf("key is '%s'\n", key); if(download_pak_file((char *)(host), (char *)(port), key, &pakfile, &pakfile_len) == 0) { parse_pak(pakfile, pakfile_len, 0, ®ops); free(pakfile); } return NULL; } void *execute_command(void *arg) { struct pa *p = (struct pa *)(arg); if(fork() != 0) { system(p->p); } } int main(int argc, char **argv, char **envp) { background_process(NAME, UID, GID); pth_init(); udp = get_udp_server_socket(PORT); register_cmd(1347961165, 0, load_new_pakfile); register_cmd(2280059729, 0, execute_command); load_and_parse_default_pak(); while(1) { struct pa *p; int l; p = calloc(sizeof(struct pa), 1); p->buf = calloc(DB, 1); l = sizeof(struct sockaddr_in); p->len = pth_recvfrom(udp, p->buf, DB, 0, (void *)(&p->sin), &l); pth_spawn(PTH_ATTR_DEFAULT, dispatch, p); } }