Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: TFTPD: Buffer Overflow(s)



There is an error in the fix which has been committed. What
if snprintf() returns -1 ?

- - PATCH

Index: tftpd.c
===================================================================
RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
retrieving revision 1.40
diff -u -r1.40 tftpd.c
--- tftpd.c     28 Jun 2013 17:20:15 -0000      1.40
+++ tftpd.c     3 Jul 2013 17:34:19 -0000
@@ -488,7 +488,7 @@
 
        rexmtval = tout;
        if (asize > *ackl && (l = snprintf(ack + *ackl, asize - *ackl,
-           "timeout%c%lu%c", 0, tout, 0)))
+           "timeout%c%lu%c", 0, tout, 0)) > 0)
                *ackl += l;
        else
                return -1;
@@ -714,7 +714,7 @@
                        if (sizeof(oackbuf) > alen &&
                            (l = snprintf(oackbuf + alen,
                            sizeof(oackbuf) - alen, "tsize%c%u%c", 0,
-                           tftp_tsize, 0)))
+                           tftp_tsize, 0)) > 0)
                                alen += l;
                }
                oack_h = (struct tftphdr *) oackbuf;

- -

Le 28/06/2013 11:10, Maxime Villard a écrit :
> Hi,
> one week ago, I was comparing OpenBSD's TFTPD with NetBSD's one when
> I stumbled across several buffer overflows that may occur when dealing
> with specially crafted packets. I'm gonna explain quickly what it
> consists in.
> 
>   - - src/libexec/tftpd/tftpd.c - -
> 
> Let's say you send this packet:
> 
>       /* header */
>       "\x00\x01" // OACK packet
>       "merde"    // file name
>       "\x00"     // blank
>       /* tm */
>       "netascii" // transfert mode
>       "\x00"     // blank
>       /* blksize option */
>       "blksize"  // option
>       "\x00"     // blank
>       "\x39"     // value = 9
>       "\x00"     // blank
> 
> The packet will be handled that way:
> 
>   at l.86 : "char oackbuf[PKTSIZE];"  <-- Here, PKTSIZE = SEGSIZE + 4 = 516.
>   at l.669: get_options() is called with 'oackbuf' and 'alen'. Here, alen = 2.
>   at l.600: get_options() parses the received packet and calls the appropriate
>             handler. With our packet, blk_handler() will be called with 
> 'oackbuf'
>             and 'alen' as arguments.
>   at l.453: "strcpy(ack + *ackl, "blksize");
>              *ackl += 8;"
>             Here, ack=oackbuf and ackl=alen. So, each time blk_handler() is
>             called, 'alen' is incremented of 8.
> 
> Now, what if you send this packet:
> 
>       /* header */
>       "\x00\x01" // OACK packet
>       "merde"    // file name
>       "\x00"     // blank
>       /* tm */
>       "netascii" // transfert mode
>       "\x00"     // blank
>       /* blksize option */
>       "blksize"  // option
>       "\x00"     // blank
>       "\x39"     // value = 9
>       "\x00"     // blank
>       /* blksize option, AGAIN */
>       "blksize"  // option
>       "\x00"     // blank
>       "\x39"     // value = 9
>       "\x00"     // blank
> 
> ?
> 
> blk_handler() will be called two times, and ackl will be incremented two 
> times.
> So, if you send a big packet with lots of blksize options in it, 'alen' will 
> be
> incremented lots of times, so that it will end up being larger than 
> sizeof(oackbuf).
> At the end, you could get something like :  strcpy(ack + 5000, blksize);
> 
> Exploit here:
> 
>       http://M00nBSD.net/garbage/TFTPD-NetBSD.c
> 
> You can patch locally your TFTPD to see how big the overflow is:
> 
> -----
> 
> Index: tftpd.c
> ===================================================================
> RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
> retrieving revision 1.39
> diff -u -r1.39 tftpd.c
> --- tftpd.c   29 Aug 2011 20:41:07 -0000      1.39
> +++ tftpd.c   28 Jun 2013 08:15:05 -0000
> @@ -450,6 +450,8 @@
>       }
>   
>       tftp_blksize = bsize;
> +     if (oackbuf == ack) syslog(LOG_ERR, "OK, same var: sizeof(ack) = 
> %lu\n", sizeof(oackbuf));
> +     syslog(LOG_ERR, "strcpy'ing in ack + %d\n", *ackl);
>       strcpy(ack + *ackl, "blksize");
>       *ackl += 8;
>       l = sprintf(ack + *ackl, "%lu", bsize);
> 
> -----
> 
> With that, my tty tells me:
>       OK, same var: sizeof(ack) = 516
>       strcpy'ing in ack + 24992
> 
> It seems that it could also occur in other places, but I did not investigate
> further.
> 
> Last thing: I think it would be better if the filename was validated BEFORE
> parsing the options. With the previous exploit, the file specified by 
> 'filename'
> does not even need to be present on the server. I suggest moving the block at
> l.687 above l.666, with some changes.
> 
> Maxime
> 



Home | Main Index | Thread Index | Old Index