Fusion level07
About
Reverse engineering level with library re-usage.
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 |
Source code
1#include "../common/common.c" 2 3#include <pth.h> 4#include <openssl/rsa.h> 5 6#include "utlist.h" 7 8struct ops { 9 void (*register_cmd)(unsigned int opcode, unsigned int flags, void *(*fp)(void *)); 10 void (*unregister_cmd)(unsigned int opcode); 11}; 12 13int parse_pak(unsigned char *pakaddr, size_t paklen, size_t base, struct ops *ops); 14 15#define DB (572) 16 17int udp; 18 19struct pa { 20 unsigned char *buf; 21 ssize_t len; 22 struct sockaddr_in sin; 23 24 unsigned char *p; 25 ssize_t remainder; 26 27}; 28 29void free_pa(struct pa *pa) 30{ 31 if(! pa) return; 32 33 if(! pa->buf) { 34 memset(pa->buf, 0, pa->len); 35 free(pa->buf); 36 } 37 38 memset(pa, 0, sizeof(struct pa)); 39 free(pa); 40} 41 42typedef struct cmdtab { 43 unsigned int opcode; 44 unsigned int flags; 45 void *(* fp)(void *); 46 struct cmdtab *prev, *next; 47} cmdtab; 48 49cmdtab *cmdtab_head; 50 51void *dispatch(void *arg) 52{ 53 struct pa *p = (struct pa *)(arg); 54 int *ip; 55 cmdtab *c = NULL; 56 57 if(p->len < sizeof(int)) goto bail; 58 59 ip = (int *)(p->buf); 60 61 p->p = p->buf + 4; 62 p->remainder = p->len - 4; 63 64 DL_FOREACH(cmdtab_head, c) { 65 if(c->opcode == ip[0]) { 66 c->fp(p); 67 break; 68 } 69 } 70 71bail: 72 free_pa(p); 73 return NULL; 74} 75 76void register_cmd(unsigned int opcode, unsigned int flags, void *(*fp)(void *)) 77{ 78 cmdtab *c; 79 80 c = calloc(1, sizeof(cmdtab)); 81 c->opcode = opcode; 82 c->flags = flags; 83 c->fp = fp; 84 85 DL_APPEND(cmdtab_head, c); 86} 87 88void unregister_cmd(unsigned int opcode) 89{ 90 cmdtab *c, *tmp; 91 92 DL_FOREACH_SAFE(cmdtab_head, c, tmp) { 93 if(c->opcode == opcode) { 94 DL_DELETE(cmdtab_head, c); 95 } 96 } 97} 98 99 100struct ops regops = { 101 .register_cmd = register_cmd, 102 .unregister_cmd = unregister_cmd 103}; 104 105#define PAKFILE "/opt/fusion/res/level07.pak" 106 107void load_and_parse_default_pak() 108{ 109 void *m; 110 int fd; 111 struct stat statbuf; 112 int status; 113 unsigned int base; 114 115 fd = open(PAKFILE, O_RDONLY); 116 if(! fd) err(1, "Unable to open %s", PAKFILE); 117 if(fstat(fd, &statbuf) == -1) err(1, "Unable to fstat %s", PAKFILE); 118 119 m = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 120 if(m == MAP_FAILED) err(1, "Unable to mmap %s", PAKFILE); 121 122 // printf("got %d bytes to process\n", statbuf.st_size); 123 124 status = parse_pak(m, statbuf.st_size, 0, ®ops); 125 126 // printf("parse_pak result: %08x\n", status); 127 128} 129 130int download_pak_file(char *host, char *port, unsigned char *key, unsigned char **pakfile, size_t *pakfile_len) 131{ 132 struct sockaddr_in sin; 133 size_t blue; 134 int ret; 135 size_t alloc; 136 int status; 137 int keyidx; 138 int keylen; 139 int i; 140 int fd; 141 142 status = -1; 143 144 keylen = strlen(key); 145 keyidx = 0; 146 147 memset(&sin, 0, sizeof(struct sockaddr_in)); 148 149 sin.sin_addr.s_addr = inet_addr(host); 150 sin.sin_port = htons(atoi(port)); 151 sin.sin_family = AF_INET; 152 153 *pakfile = NULL; 154 *pakfile_len = 0; 155 156 fd = socket(AF_INET, SOCK_STREAM, 0); 157 if(fd == -1) return; 158 if(pth_connect(fd, (void *)(&sin), sizeof(struct sockaddr_in)) == -1) goto closefd; 159 160 if(pth_read(fd, &alloc, sizeof(alloc)) != sizeof(alloc)) goto closefd; 161 162 blue = 0; 163 *pakfile = calloc(alloc, 1); 164 if(*pakfile == NULL) goto closefd; 165 *pakfile_len = alloc; 166 167 while(alloc - blue) { 168 ret = pth_read(fd, (*pakfile) + blue, alloc - blue); 169 170 if(ret == -1) goto freemem; 171 if(ret == 0) goto freemem; 172 173 for(i = 0; i < ret; i++) { 174 //printf("key byte is %02x/%c\n", key[keyidx], key[keyidx]); 175 (*pakfile)[blue + i] ^= key[keyidx]; 176 keyidx = (keyidx + 1) % keylen; 177 } 178 179 blue += ret; 180 } 181 182 status = 0; 183 goto closefd; 184 185freemem: 186 free(*pakfile); 187 *pakfile = NULL; 188 *pakfile_len = 0; 189 190closefd: 191 close(fd); 192 return status; 193 194} 195 196void *load_new_pakfile(void *arg) 197{ 198 struct pa *p = (struct pa *)(arg); 199 unsigned char *q; 200 unsigned char *host, *port, *key = NULL; 201 unsigned char *pakfile; 202 size_t pakfile_len; 203 204 host = p->p; 205 q = strchr(p->p, '|'); 206 if(! q) return NULL; 207 *q++ = 0; 208 port = q; 209 q = strchr(q, '|'); 210 if(! q) return NULL; 211 *q++; 212 key = q; 213 214 if(strlen(key) < 8) return NULL; 215 216 // printf("key is '%s'\n", key); 217 218 if(download_pak_file((char *)(host), (char *)(port), key, &pakfile, &pakfile_len) == 0) { 219 parse_pak(pakfile, pakfile_len, 0, ®ops); 220 free(pakfile); 221 } 222 223 return NULL; 224} 225 226void *execute_command(void *arg) 227{ 228 struct pa *p = (struct pa *)(arg); 229 if(fork() != 0) { 230 system(p->p); 231 } 232} 233 234int main(int argc, char **argv, char **envp) 235{ 236 background_process(NAME, UID, GID); 237 238 pth_init(); 239 240 udp = get_udp_server_socket(PORT); 241 242 register_cmd(1347961165, 0, load_new_pakfile); 243 register_cmd(2280059729, 0, execute_command); 244 245 load_and_parse_default_pak(); 246 247 while(1) { 248 struct pa *p; 249 int l; 250 251 p = calloc(sizeof(struct pa), 1); 252 p->buf = calloc(DB, 1); 253 l = sizeof(struct sockaddr_in); 254 p->len = pth_recvfrom(udp, p->buf, DB, 0, (void *)(&p->sin), &l); 255 256 pth_spawn(PTH_ATTR_DEFAULT, dispatch, p); 257 } 258}