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, &regops);
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, &regops);
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}

Discussion