Difference between revisions of "Debian OpenSSL"
m (→OpenSSL) |
m (→Blacklists) |
||
Line 17: | Line 17: | ||
* http://www.red-bean.com/~maxb/ contains also RSA-1024 and RSA-1023 but not all archs, to be converted: |
* http://www.red-bean.com/~maxb/ contains also RSA-1024 and RSA-1023 but not all archs, to be converted: |
||
cat $1 | sed 's/^............//' | sort > blacklist.$(echo $1|cut -c 1-8|tr a-z A-Z) |
cat $1 | sed 's/^............//' | sort > blacklist.$(echo $1|cut -c 1-8|tr a-z A-Z) |
||
+ | ====DELETE ALL DSA KEYS==== |
||
+ | Ok there are nice DSA blacklists but actually [http://blog.sesse.net/blog/tech/2008-05-14-17-21_some_maths.html if a good DSA key was used on a bad machine, the key is compromised]! (thanks [http://roland.entierement.nu/blog/2008/05/15/branle-bas-sshssl.html Roland]) |
||
====Check==== |
====Check==== |
Revision as of 23:42, 16 May 2008
This is a compilation of my notes on this matter
Links
- http://www.debian.org/security/2008/dsa-1576
- http://www.debian.org/security/key-rollover/
- http://metasploit.com/users/hdm/tools/debian-openssl/
- http://www.milw0rm.com/exploits/5622
- http://www.yobi.be/files/blacklist.RSA-1024 32-bit Intel platform
misc
OpenSSH
Blacklists
- Current official blacklists cover RSA-2048 and DSA-1024 keys as generated on 32-bit little-endian, 64-bit little-endian and 32-bit big-endian systems
- Version Including 4096bit RSA fingerprints: http://love.hole.fi/atte/openssh-blacklist/openssh-blacklist_0.1.2_all.deb
- debian_ssh_scan_v3.tar.bz2 now including DSA 1024, RSA 2048 and RSA 4096 bit keys. Check tool dusplays also PID so very easy to generate the corresponding key.
- http://www.red-bean.com/~maxb/ contains also RSA-1024 and RSA-1023 but not all archs, to be converted:
cat $1 | sed 's/^............//' | sort > blacklist.$(echo $1|cut -c 1-8|tr a-z A-Z)
DELETE ALL DSA KEYS
Ok there are nice DSA blacklists but actually if a good DSA key was used on a bad machine, the key is compromised! (thanks Roland)
Check
Etch version gives you openssh-blacklist package and ssh-vulnkey in openssh-client
This Etch version has a sshd which checks all client connections against the blacklist so even if the keys are still in authorized_keys you should be safe
On Lenny/Sid, you can extract the Etch /etc/ssh/blacklist* and /usr/bin/ssh-vulnkey and use them
To checks all my vservers I did this [{{#file: ssh-myvuln.sh}} little script]:
#!/bin/bash
function filter () {
sed 's/\(Not blacklisted: \)/\1 /;
s/\(COMPROMISED: \)/\1 /;
s/222$/.broken/;
'
}
function scan () {
#echo $1
ssh-vulnkey $1 | filter
}
function checkpath () {
mypath="$1"
echo "===== server keys at $mypath ====="
for i in $(ls ${mypath}etc/ssh/*_key 2>/dev/null); do scan $i; done
echo "===== discarded broken server keys at $mypath ====="
for i in $(ls ${mypath}etc/ssh/*_key.pub.broken 2>/dev/null); do cp $i ${i%%.broken}222; scan ${i%%.broken}222; rm ${i%%.broken}222; done
echo "===== client keys at $mypath ====="
for i in $(ls ${mypath}root/.ssh/id* 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}home/*/.ssh/id* 2>/dev/null); do scan $i; done
for v in $(ls ${mypath}etc/passwd 2>/dev/null); do
for u in $(cat $v|awk -F: '{print $6}'|sort|uniq|egrep -v "^(/root|/home/[a-z0-9]*)$"|sed 's#^/##'); do
for i in $(ls ${v%%etc/passwd}${u}/.ssh/id* 2>/dev/null); do scan $i; done
done
done
echo "===== authorized external client keys at $mypath ====="
for i in $(ls ${mypath}root/.ssh/*_keys* 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}home/*/.ssh/*_keys* 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}var/lib/backuppc/.ssh/*_keys* 2>/dev/null); do scan $i; done
echo "===== known external server keys at $mypath ====="
for i in $(ls ${mypath}etc/ssh/known_hosts 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}root/.ssh/known_hosts 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}home/*/.ssh/known_hosts 2>/dev/null); do scan $i; done
for i in $(ls ${mypath}var/lib/backuppc/.ssh/known_hosts 2>/dev/null); do scan $i; done
}
checkpath "/"
checkpath "/home/vservers/*/"
To get a resume sortable on the fingerprint:
ssh-myvuln.sh |grep ":..:..:"|sed 's/\(.\).* \(..:..:..:..:..:..:..:..:..:..:..:..:..:..:..:..\) \(.*\)/\2 \1 hostname:\3/'|sort > mykeys
To get a list to check against a blacklist:
cat mykeys |cut -c 19,20,22,23,25,26,28,29,31,32,34,35,37,38,40,41,43,44,46,47|sort|uniq > myfing cat myfing blacklist | sort | uniq -d
Scan
[{{#file: dowkd.pl.patch}} Patch] against dowkd.pl for fetching keys from /etc/ssh/blacklist*
--- dowkd.pl 2008-05-16 16:00:53.000000000 +0200
+++ dowkd.pl 2008-05-16 15:55:23.000000000 +0200
@@ -47,19 +47,29 @@
my $db;
my %db;
+my $blacklistdir='/etc/ssh';
+
sub create_db () {
$db = tie %db, 'DB_File', $db_file, O_RDWR | O_CREAT, 0777, $DB_BTREE
or die "error: could not open database: $!\n";
$db{''} = $db_version;
- while (my $line = <DATA>) {
- next if $line =~ /^\**$/;
- chomp $line;
- $line =~ /^[0-9a-f]{32}$/ or die "error: invalid data line";
- $line =~ s/(..)/chr(hex($1))/ge;
- $db{$line} = '';
+ opendir(my $dh, $blacklistdir) or die "Cannot open dir $blacklistdir : $!\n";
+ while(my $e=readdir($dh)) {
+ next if $e =~ m/^\.\.?$/;
+ next unless $e =~ m/^blacklist/;
+print STDERR "Reading $e\n";
+ open (my $fh, $blacklistdir.'/'.$e) or die "Cannot open file $e : $!\n";
+ while (my $line = <$fh>) {
+ next if $line =~ /^\**$/;
+ next if $line =~ /^#/;
+ chomp $line;
+ $line =~ /^[0-9a-f]{20}$/ or die "error: invalid data line";
+#print STDERR "Line= $line\n";
+ $line =~ s/(..)/chr(hex($1))/ge;
+ $db{$line} = '';
+ }
}
-
$db->sync;
}
@@ -106,6 +116,7 @@
sub check_hash ($$) {
my ($name, $hash) = @_;
++$keys_found;
+ $hash =~ s/^......//;
if (exists $db{$hash}) {
++$keys_vulnerable;
print "$name: weak key\n";
for ip in $(netenum 85.17.183.154/27); do ./dowkd.pl host $ip; done
Netenum is part of irpas
Renew server keys
mv /etc/ssh/ssh_host_dsa_key /etc/ssh/ssh_host_dsa_key.broken
mv /etc/ssh/ssh_host_dsa_key.pub /etc/ssh/ssh_host_dsa_key.pub.broken
mv /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key.broken
mv /etc/ssh/ssh_host_rsa_key.pub /etc/ssh/ssh_host_rsa_key.pub.broken
dpkg-reconfigure openssh-server
ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key
ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
Generate vuln keys & blacklists
To generate yourself the vulnerable key set:
wget http://sugar.metasploit.com/ubunturoot.tar.bz2 wget http://metasploit.com/users/hdm/tools/debian-openssl/dokeygen.sh
Put dokeygen.sh in the root of the ubuntu filesystem Example for RSA 1024 (but RSA keys were upgraded by default to 2048 since Sept 2005)
sudo chroot ubunturoot
for ((i=1;i<32768;i++)); do
echo $i;
/dokeygen.sh $i -t rsa -b 1024 -f /tmp/rsa_1024_$i;
done
Ideally keys & blacklists must be generated on 32 & 64-bit platforms, little & big endian
Then to extract the fingerprints to make the blacklist
for ((i=1;i<32768;i++)); do
if [ -e rsa_1024_$i ]; then
echo $i;
f=$(ssh-keygen -l -f rsa_1024_$i|sed 's/1024 \([0-9a-f:]\+\) rsa.*/\1/;s/://g')
mv rsa_1024_$i $f-$i
mv rsa_1024_$i.pub $f-$i.pub
echo $f |sed 's/^............//'>> blacklist.RSA-1024
fi
done
Exploiting a vuln key:
Example of a fingerprint found in an authorized_keys file:
ssh -i 491f487168134647f111a882c8a04059-21223 bibi@hostname bibi@hostname:~$
OpenSSL
Check
wget https://launchpad.net/ubuntu/hardy/+source/openssl-blacklist/0.1-0ubuntu0.8.04.2/+files/openssl-blacklist_0.1-0ubuntu0.8.04.2.tar.gz tar xzf openssl-blacklist_0.1-0ubuntu0.8.04.2.tar.gz cd openssl-blacklist-0.1 Edit debian/control and cleans the dependence on openssl for Ubuntu fakeroot debian/rules binary cd .. sudo dpkg -i openssl-blacklist_0.1-0ubuntu0.8.04.2_all.deb
Now you have openssl-vulnkey tool
But this works only on private key files.
Here is a [{{#file: openssl-vulnkey.patch}} patch] to get it working against public certificate files (so you can check certifs of your favorite https sites, e.g. by exporting the certifs with FF)
--- openssl-vulnkey 2008-05-16 19:56:51.000000000 +0200
+++ openssl-vulncert 2008-05-16 19:56:36.000000000 +0200
@@ -55,7 +55,7 @@
def get_bits(file):
'''Find bit length of file'''
- rc, report = cmd(['openssl', 'rsa', '-text', '-in', file])
+ rc, report = cmd(['openssl', 'x509', '-text', '-in', file])
if rc != 0:
try:
print >> sys.stderr, "ERROR:\n%s" % (report)
@@ -64,16 +64,16 @@
return ""
for line in report:
- if "Private-Key: (1024" in report:
+ if "Public Key: (1024" in report:
return "1024"
- elif "Private-Key: (2048" in report:
+ elif "Public Key: (2048" in report:
return "2048"
return ""
def get_modulus(file):
'''Find modulus of file'''
- rc, report = cmd(['openssl', 'rsa', '-noout', '-modulus', '-in', file])
+ rc, report = cmd(['openssl', 'x509', '-noout', '-modulus', '-in', file])
if rc != 0:
try:
print >> sys.stderr, "ERROR: %d:\n%s" % (rc, report)
Scan
Next step is to get the certificates chain from the distant website
Here is [{{#file: fetch-https-1cert.c}} fetch-https-1cert.c] to do the job
/**
* Fetch an HTTPS page and display the certificate chain.
Sources:
http://curl.haxx.se/mail/lib-2005-06/0106.html
http://openvpn.net/archive/openvpn-devel/2005-12/msg00000.html
http://www.mail-archive.com/debian-bugs-closed@lists.debian.org/msg173845.html
*/
#include <assert.h>
#include <stdio.h>
#include <curl/curl.h>
#include <openssl/ssl.h>
char error_buffer[CURL_ERROR_SIZE] = "";
CURLcode go(CURL *curl, char *url);
CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx);
void print_certificate(X509 *cert);
/* arrays for certificate chain and errors */
#define MAX_CERTS 20
X509 *certificate[MAX_CERTS];
long certificate_error[MAX_CERTS];
char site[256];
int count=0;
int main(int argc, char *argv[])
{
unsigned int i;
CURL *curl;
CURLcode code;
assert(argc == 2);
for (i = 0; i != MAX_CERTS; i++) {
certificate[i] = 0;
certificate_error[i] = X509_V_OK;
}
curl = curl_easy_init();
assert(curl);
strncpy(site, argv[1], 256);
site[255]=0;
code = go(curl, argv[1]);
if (code != CURLE_OK)
fprintf(stderr, "Error %u: %s\n%s\n",
code,
curl_easy_strerror(code),
error_buffer);
curl_easy_cleanup(curl);
return 0;
}
CURLcode go(CURL *curl, char *url)
{
CURLcode code;
FILE* devnull = NULL;
devnull = fopen("/dev/null", "w+");
code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
if (code != CURLE_OK)
return code;
code = curl_easy_setopt(curl, CURLOPT_URL, url);
if (code != CURLE_OK)
return code;
// code = curl_easy_setopt(curl, CURLOPT_WRITEHEADER, stdout);
// if (code != CURLE_OK)
// return code;
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, devnull);
if (code != CURLE_OK)
return code;
code = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);
if (code != CURLE_OK)
return code;
/* fetch the page even if verifying the certificates fails */
code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
if (code != CURLE_OK)
return code;
code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
if (code != CURLE_OK)
return code;
code = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun);
if (code != CURLE_OK)
return code;
code = curl_easy_perform(curl);
fclose(devnull);
return code;
}
CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm)
{
SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
return CURLE_OK;
}
static void
extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int size)
{
int lastpos = -1;
int tmp = -1;
X509_NAME_ENTRY *x509ne = 0;
ASN1_STRING *asn1 = 0;
unsigned char *buf = 0;
int nid = OBJ_txt2nid(field_name);
*out = '\0';
do {
lastpos = tmp;
tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos);
} while (tmp > 0);
/* Nothing found */
if (lastpos == -1)
return;
x509ne = X509_NAME_get_entry(x509, lastpos);
if (!x509ne)
return;
asn1 = X509_NAME_ENTRY_get_data(x509ne);
if (!asn1)
return;
tmp = ASN1_STRING_to_UTF8(&buf, asn1);
if (tmp <= 0)
return;
strncpy(out, buf, size);
OPENSSL_free(buf);
}
int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
int err = X509_STORE_CTX_get_error(x509_ctx);
FILE *peercert_file;
char s[256];
char ii[256];
/* save the certificate by incrementing the reference count and
* keeping a pointer */
if (depth < MAX_CERTS && !certificate[depth]) {
certificate[depth] = cert;
certificate_error[depth] = err;
cert->references++;
}
extract_x509_field_ssl (X509_get_subject_name(cert), "CN", s, 256);
/* write peer-cert in tmp-file */
if (s[0]==0)
{
strcpy(s, site+8);
}
sprintf(ii, "%d", count++);
strcat(s, ii);
printf("Writing cert in: %s\n", s);
peercert_file = fopen(s, "w+");
if(!peercert_file)
{
printf("Failed to open file : %s", s);
return 1;
}
if(PEM_write_X509(peercert_file,cert)<0)
{
printf("Failed to write peer certificate in PEM format");
fclose(peercert_file);
return 1;
}
fclose(peercert_file);
return 1;
}
So now empowered with Google we can do sth like this:
#!/bin/bash
REQ=$1
REQ=${REQ:-site:be}
start=0
for ((i=$start;i<10;i++)); do
echo "Fetching 100 results starting from ${i}00"
for site in $(wget -q -O - --header "User-Agent: Mozilla/5.0" "http://www.google.fr/search?q=inurl%3Ahttps+$REQ&start=${i}00&num=100" |\
egrep -o "https://[a-z0-9.-]+"|\
sort|\
uniq); do
./fetch-https-1cert $site |\
cut -c 18- |\
xargs -d '\n' -l1 -r ./openssl-vulncert | sed "s#\$# (from $site)#"
done
done
./scanhttps |grep COMPROMISED|uniq -w 53
COMPROMISED: 942c267f69f53567053ad77f980f2d8980270759 leclea.be1 (from https://leclea.be) COMPROMISED: 9c5526d7d2d152e8ac437a669741a6ed6bed78a9 www.phpcompta.be0 (from https://phpcompta.be) COMPROMISED: 97c7fdf8136f5c47d3aa2b9667dd252f6af7ebf6 phpcompta.be2 (from https://phpcompta.be) COMPROMISED: fb62587b6fd13b6b7de54fcf10de77f586ac3362 Dr. Robert Necesseter0 (from https://tirna.nog.be) COMPROMISED: a7ae2ec301f7b7b844371bc76c20ee0747c32f15 www.pptickets.be4 (from https://www.pptickets.be) COMPROMISED: bbc4679d1ddccb716593c069708ad2cb21115a47 a248.e.akamai.net1 (from https://www.nokia.be) COMPROMISED: 4da0544ef1cf3cac7e166592e0900d6be2a92fae www.smartsalto.be2 (from https://www.smartsalto.be) COMPROMISED: 1b7da681c247784a6b9e1a1b2c15dcd091b5aa75 securehomes.esat.kuleuven.be2 (from https://securehomes.esat.kuleuven.be)
OpenVPN
It's not about the SSL keys, those can be checked with openssl-vulnkey.
It's about the shared static keys (openvpn -genkey)
wget https://launchpad.net/ubuntu/hardy/+source/openvpn-blacklist/0.1-0ubuntu0.8.04.1/+files/openvpn-blacklist_0.1-0ubuntu0.8.04.1.tar.gz tar xzf openvpn-blacklist_0.1-0ubuntu0.8.04.1.tar.gz cd openvpn-blacklist-0.1 fakeroot debian/rules binary cd .. sudo dpkg -i openvpn-blacklist_0.1-0ubuntu0.8.04.1_all.deb
Now you have openvpn-vulnkey tool
Others
- encfs
- My key is older, ouf!
Status
- zeus
- hera
- themis
- olympe
- mercure
- venus