Stack-based Buffer Overflow in the VPN Software tinc for Authenticated Peers

April 22, 2013 at 11:42 PM | categories: advisory

The VPN software tinc is affected by a buffer overflow in a protocol parser, which results in a memory corruption and possibly a code execution. An attacker might trigger this vulnerability from a remote side via the network. Triggering this vulnerability requires being a known and authenticated peer in order to speak the so-called meta protocol.

CVE-2013-1428 was assigned to this vulnerability.

Affected Products

The vulnerability is known to be present in tinc version 1.1-pre6 and 1.0.19. Other versions might be affected as well. Version 1.0.19 is the default version on Ubuntu Linux 12.10 and is available in the FreeBSD ports collection.

Recommendation

The vulnerability is fixed in tinc versions 1.0.21 and 1.1pre7. It is recommended to upgrade existing installations.

Details

In net_packet.c, the function receive_tcppacket() declares a stack-local structure and this structure contains a buffer of 1661 elements. The function uses memcpy() to copy data from a helper buffer. This helper buffer contains network data and might become larger than the destination buffer. If an attacker sends a specially crafted packet, he might overwrite memory beyond the buffer boundaries.

Net.h:

typedef struct vpn_packet_t {
  length_t len;   /* the actual number of bytes in the `data' field */
  int priority;   /* priority or TOS */
  uint32_t seqno; /* 32 bits sequence number (network byte order of course) */
  uint8_t data[MAXSIZE]; // auditor remark: MAXSIZE == 1661
} vpn_packet_t;

Net_packet.c:

void receive_tcppacket(connection_t *c, const char *buffer, int len) {
  vpn_packet_t outpkt;

  outpkt.len = len;
  if(c->options & OPTION_TCPONLY)
    outpkt.priority = 0;
  else
    outpkt.priority = -1;
  // auditor remark: len > outpkt.data[MAXSIZE] ?
  memcpy(outpkt.data, buffer, len); 

  receive_packet(c->node, &outpkt);
}

Meta.c:

bool receive_meta(connection_t *c) {
  int inlen;
  char inbuf[MAXBUFSIZE]; // MAXSIZE +128
  char *bufp = inbuf, *endp;
[...]
  inlen = recv(c->socket, inbuf, sizeof inbuf - c->inbuf.len, 0);
[...]
  do {
[...]
    while(c->inbuf.len) {
      /* Are we receiving a TCPpacket? */

      if(c->tcplen) {
    char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
    if(!tcpbuffer)
      break;
    if(!c->node) {
[...]
    } else {
      if(c->allow_request == ALL) {
        receive_tcppacket(c, tcpbuffer, c->tcplen);
      } 
[...]
    }
        c->tcplen = 0;
      }
[...]
    }
  } while(inlen);

  return true;
}

According to receive_meta(), it is required that all meta protocol commands are enabled for a client in order to call receive_tcppacket(). These commands are enabled, if the is client successfully authenticated.

Proof of Concept

This python script mocks the authentication procedure and overflows the buffer afterwards, which results in a memory corruption as shown below.

Linux:

$ sudo /usr/sbin/tincd -D -d 5 -c /usr/local/etc/tinc/testnet/
tincd 1.0.19 (Jun 29 2012 14:10:44) starting, debug level 1
/dev/net/tun is a Linux tun/tap device (tun mode)
Unconfigured tinc-up script, please edit!
Listening on 0.0.0.0 port 655
Listening on :: port 655
Ready
Connection from 10.0.0.123 port 44645
Connection with testnode2 (10.0.0.123 port 44645) activated
*** buffer overflow detected ***: /usr/sbin/tincd terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x65)[0xb749f065]
/lib/i386-linux-gnu/libc.so.6(+0x102e1a)[0xb749de1a]
/usr/sbin/tincd[0x804f42b]
/usr/sbin/tincd[0x804e12f]
/usr/sbin/tincd[0x804ec22]
/usr/sbin/tincd[0x804b71c]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb73b44d3]
/usr/sbin/tincd[0x804b8b9]
======= Memory map: ========
08048000-08069000 r-xp 00000000 08:01 308865     /usr/sbin/tincd
08069000-0806a000 r--p 00020000 08:01 308865     /usr/sbin/tincd
0806a000-0806b000 rw-p 00021000 08:01 308865     /usr/sbin/tincd
0806b000-080dc000 rw-p 00000000 00:00 0 
096c6000-096e7000 rw-p 00000000 00:00 0          [heap]
b7369000-b7385000 r-xp 00000000 08:01 132074     /lib/i386-linux-gnu/libgcc_s.so.1
b7385000-b7386000 r--p 0001b000 08:01 132074     /lib/i386-linux-gnu/libgcc_s.so.1
b7386000-b7387000 rw-p 0001c000 08:01 132074     /lib/i386-linux-gnu/libgcc_s.so.1
b739a000-b739b000 rw-p 00000000 00:00 0 
b739b000-b753e000 r-xp 00000000 08:01 132049     /lib/i386-linux-gnu/libc-2.15.so
b753e000-b753f000 ---p 001a3000 08:01 132049     /lib/i386-linux-gnu/libc-2.15.so
b753f000-b7541000 r--p 001a3000 08:01 132049     /lib/i386-linux-gnu/libc-2.15.so
b7541000-b7542000 rw-p 001a5000 08:01 132049     /lib/i386-linux-gnu/libc-2.15.so
b7542000-b7545000 rw-p 00000000 00:00 0 
b7545000-b7548000 r-xp 00000000 08:01 132064     /lib/i386-linux-gnu/libdl-2.15.so
b7548000-b7549000 r--p 00002000 08:01 132064     /lib/i386-linux-gnu/libdl-2.15.so
b7549000-b754a000 rw-p 00003000 08:01 132064     /lib/i386-linux-gnu/libdl-2.15.so
b754a000-b756b000 r-xp 00000000 08:01 304244     /usr/lib/i386-linux-gnu/liblzo2.so.2.0.0
b756b000-b756c000 r--p 00020000 08:01 304244     /usr/lib/i386-linux-gnu/liblzo2.so.2.0.0
b756c000-b756d000 rw-p 00021000 08:01 304244     /usr/lib/i386-linux-gnu/liblzo2.so.2.0.0
b756d000-b756e000 rw-p 00000000 00:00 0 
b756e000-b7585000 r-xp 00000000 08:01 132183     /lib/i386-linux-gnu/libz.so.1.2.7
b7585000-b7586000 r--p 00016000 08:01 132183     /lib/i386-linux-gnu/libz.so.1.2.7
b7586000-b7587000 rw-p 00017000 08:01 132183     /lib/i386-linux-gnu/libz.so.1.2.7
b7587000-b7719000 r-xp 00000000 08:01 182182     /lib/i386-linux-gnu/libcrypto.so.1.0.0
b7719000-b7728000 r--p 00192000 08:01 182182     /lib/i386-linux-gnu/libcrypto.so.1.0.0
b7728000-b772f000 rw-p 001a1000 08:01 182182     /lib/i386-linux-gnu/libcrypto.so.1.0.0
b772f000-b7732000 rw-p 00000000 00:00 0 
b7744000-b7747000 rw-p 00000000 00:00 0 
b7747000-b7748000 r-xp 00000000 00:00 0          [vdso]
b7748000-b7768000 r-xp 00000000 08:01 132027     /lib/i386-linux-gnu/ld-2.15.so
b7768000-b7769000 r--p 0001f000 08:01 132027     /lib/i386-linux-gnu/ld-2.15.so
b7769000-b776a000 rw-p 00020000 08:01 132027     /lib/i386-linux-gnu/ld-2.15.so
bfded000-bfe0e000 rw-p 00000000 00:00 0          [stack]

FreeBSD:

root@freebsd:/root # tincd -D -d 5 -c /usr/local/etc/tinc/
tincd 1.0.19 (Apr  2 2013 18:11:46) starting, debug level 1
Cannot open config file /usr/local/etc/tinc//hosts/testnode3: No such file or directory
/dev/tun0 is a Generic BSD tun device
Listening on :: port 655
Listening on 0.0.0.0 port 655
Ready
Connection from 10.0.0.123 port 48949
Connection with testnode2 (10.0.0.123 port 48949) activated
Got fatal signal 10 (Bus error: 10)
Not restarting.

Timeline

  • 2013-04-11: Informed the author of tinc and initial advisory
  • 2013-04-12: Fix available
  • 2013-04-13: Advisory updated
  • 2013-04-22: New version of tinc published
  • 2013-04-22: Advisory published
  • 2013-12-12: Tobias Ospelt published a metaploit module for exploiting this vulnerability.

Acknowledgment

Many thanks to Guus Sliepen and the Debian Security Team for fixing and coordinating this issue.

Contact

Martin Schobert schobert@sitsec.net