≡ Menu

How To Test SSLv2 DROWN Attack Vulnerability Using Python Script (And Solution to Fix the DROWN Attack on Apache and NginX)

DROWN stands for Decrypting RSA with Obsolete and Weakened eNcryption.

This is from Vulnerability Note VU#583776: Network traffic encrypted using RSA-based SSL certificates over SSLv2 may be decrypted by the DROWN attack.

This is also referred as CVE-2016-0800.

To fix the problem, you should simply disable support for SSLv2 on servers that are using RSA-based SSL certificates. SSLv2 has been deprecated since 2011. There is no reason for you to use SSLv2 anymore.

Two Methods to Test DROWN Vulnerability

There are two ways you can test for DROWN vulnerability:

  1. Go to drownattack test site, and enter the domain name or ip-address of the site that you want to test.
  2. If you want to test the servers that are running behind your firewall, or if you want to automate testing all your servers from command line, use the python script that was developed by Hubert Kario of RedHat as explained below.

Install Python DROWN Test Script

You don’t need to do this on the server that you want to test. You can install the following python script on any of your server (For example, on a dev server), and test all your other servers from this server where this python script is installed.

For this, you should have Python 2.6 or above.

# python --version
Python 2.6.6

You should also have git installed on your system:

# git --version
git version 1.7.1

Create a drown directory.

cd ~
mkdir drown
cd drown

Get the TLSFuzzer using git clone

# git clone https://github.com/tomato42/tlsfuzzer
Initialized empty Git repository in /root/drown/tlsfuzzer/.git/
remote: Counting objects: 480, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 480 (delta 5), reused 0 (delta 0), pack-reused 470
Receiving objects: 100% (480/480), 1.30 MiB | 327 KiB/s, done.
Resolving deltas: 100% (302/302), done.

Checkout the ssl2 branch

# cd tlsfuzzer

# git checkout ssl2
Branch ssl2 set up to track remote branch ssl2 from origin.
Switched to a new branch 'ssl2'

At this stage, you should see the following files under ~/drown/tlsfuzzer directory

# ls
build-requirements.txt  docs  LICENSE  Makefile  README.md  requirements.txt  scripts  setup.py  tests  tlsfuzzer

Next, get tlslite-ng, which is an open source python library that implements SSL and TLS cryptographic protocols.

# git clone https://github.com/tomato42/tlslite-ng .tlslite-ng
Initialized empty Git repository in /root/drown/tlsfuzzer/.tlslite-ng/.git/
remote: Counting objects: 4821, done.
remote: Total 4821 (delta 0), reused 0 (delta 0), pack-reused 4821
Receiving objects: 100% (4821/4821), 1.55 MiB | 137 KiB/s, done.
Resolving deltas: 100% (3570/3570), done.

Next create the appropriate link for the tlslite that we just downloaded above.

# ln -s .tlslite-ng/tlslite tlslite

Checkout the sslv2 branch.

# cd .tlslite-ng/

# git checkout sslv2
Branch sslv2 set up to track remote branch sslv2 from origin.
Switched to a new branch 'sslv2'

# cd ~/drown/tlsfuzzer

Get the ECDSA cryptography python script.

# git clone https://github.com/warner/python-ecdsa .python-ecdsa
Initialized empty Git repository in /root/drown/tlsfuzzer/.python-ecdsa/.git/
remote: Counting objects: 485, done.
remote: Total 485 (delta 0), reused 0 (delta 0), pack-reused 485
Receiving objects: 100% (485/485), 180.60 KiB, done.
Resolving deltas: 100% (289/289), done.

Create appropriate link for the python ECSDA script.

# ln -s .python-ecdsa/ecdsa ecdsa

Test DROWN Vulnerability Using Python Script – Not Vulnerable Example

Finally, execute the DROWN python script as shown below. Change the ip-address appropriate to the server that you are testing. You can also use domain name instead of ip-address here.

# PYTHONPATH=. python scripts/test-sslv2-force-export-cipher.py -h 192.168.101.2 -p 443

Connect with TLSv1.0 EXP-RC4-MD5 ...OK
Connect with SSLv2 EXP-RC4-MD5 ...OK
Connect with SSLv3 EXP-RC4-MD5 ...OK
Connect with TLSv1.0 EXP-RC2-CBC-MD5 ...OK
Connect with SSLv3 EXP-RC2-CBC-MD5 ...OK
Connect with SSLv2 EXP-RC2-CBC-MD5 ...OK

Test end
successful: 6
failed: 0

Note: You should see 6 OK’s above. You should also see “failed: 0”.

Test DROWN Vulnerability Using Python Script – Vulnerable Example

The following is executed on a server that was vulnerable to DROWN attack. This is what you’ll see when it is vulnerable.

# PYTHONPATH=. python scripts/test-sslv2-force-export-cipher.py -h 192.168.101.3 -p 443
Connect with TLSv1.0 EXP-RC4-MD5 ...OK

Connect with SSLv2 EXP-RC4-MD5 ...
Error encountered while processing node <tlsfuzzer.expect.ExpectSSL2Alert object at 0x2259810> (child: <tlsfuzzer.expect.ExpectClose object at 0x2259890>) with last message being: <tlslite.messages.Message object at 0x2259c50>
Error while processing
Traceback (most recent call last):
  File "scripts/test-sslv2-force-export-cipher.py", line 109, in main
    runner.run()
  File "/root/drown/tlsfuzzer/tlsfuzzer/runner.py", line 151, in run
    RecordHeader2)))
AssertionError: Unexpected message from peer: Handshake(58)

Connect with SSLv3 EXP-RC4-MD5 ...OK
Connect with TLSv1.0 EXP-RC2-CBC-MD5 ...OK
Connect with SSLv3 EXP-RC2-CBC-MD5 ...OK
Connect with SSLv2 EXP-RC2-CBC-MD5 ...OK

Test end
successful: 5
failed: 1

Fix the DROWN Attack Issue

In the above DROWN vulnerable scenario, one of the test case failed. To fix this issue, add the following line to the Apache’s httpd.conf, and restart the Apache.

# vi httpd.conf
SSLProtocol All -SSLv2 -SSLv3

If you are running NginX, make sure SSLv2 is not listed in the configuration file as shown below.

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

In Apache, we should explicitly say “-SSLv2” to disable SSLv2. But in NginX, when you don’t list SSLv2, it is disabled.

After the above fix, the python DROWN test script didn’t report the issue on that particular server anymore.

Apart from Apache and NginX, if you are running Postfix for your email server, you should disable SSLv2 on your email server also.

Also, upgrade your OpenSSL to the latest version. In the new version, OpenSSL team also have disabled the SSLv2 by default at build-time. OpenSSL team has this suggestion: Upgrade 1.0.2 version to 1.0.2g; and upgrade 1.0.1 version to 1.0.1s.

Additional Reference:

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

{ 11 comments… add one }

  • André Rainho March 3, 2016, 9:50 am

    Hello

    I got this issue when running test-sslv2-force-export-cipher.py.
    I installed the requirements with
    $ pip2 install -r requirements.txt

    I have the recommend version of tlslite installed
    $ pip2 list | grep tlslite
    tlslite-ng (0.6.0a4)

    $ PYTHONPATH=. python2 scri
    pts/test-sslv2-force-export-cipher.py -h example.com -p 443

    Traceback (most recent call last):
    File “scripts/test-sslv2-force-export-cipher.py”, line 9, in
    from tlsfuzzer.runner import Runner
    File “/home/Code/drown_attack/tlsfuzzer/tlsfuzzer/runner.py”, line 11, in
    from tlslite.constants import ContentType, HandshakeType, AlertLevel, \
    ImportError: cannot import name SSL2HandshakeType

  • Newerth March 4, 2016, 4:18 am

    I assume a timeout result is fine as well. Is that correct?

  • J March 4, 2016, 12:01 pm

    Is it possible to scan an entire network rather than one ip at a time?

    Thanks,
    J

  • K March 4, 2016, 1:22 pm

    J @ no. impossible

  • paul March 5, 2016, 5:14 am

    program all ssl/tls certs for delivery FAILURE for all connections below 112 bits for cypher suites & browsers as well as anything that uses SSLv2——paul-STOP DROWN MENACE NOW

  • unknown March 6, 2016, 8:33 am

    Things like nmap don’t exist!
    I repeat, things like nmap don’t exist!

    I repeat, things like nmap don’t exist!

  • Jasen March 8, 2016, 5:00 pm

    I get this banner, between the last “OK” and “Test end”

    Note: SSLv2 was officially deprecated (MUST NOT use) in 2011, see
    RFC 6176.
    If one or more of the tests fails because of error in form of

    Unexpected message from peer: Handshake()

    With any number inside parethensis, and the server is
    configured to not support SSLv2, it means it most
    likely is vulnerable to CVE-2015-3197 and CVE-2016-0800.
    In case it’s a RC4 or 3DES cipher, you may verify that it
    really supports it using:
    test-sslv2-connection.py

  • pro March 9, 2016, 2:29 am

    I’m no Phyton coder:
    How do I have to change the code to test other ciphers like SSL2_RC4_128_WITH_MD5
    or SSL2_DES_192_EDE3_CBC_WITH_MD5 …

    Thank you.

  • Andrea March 9, 2016, 9:26 am

    I get this:

    Traceback (most recent call last):
    File “/root/Desktop/drownAttack/tlsfuzzer/scripts/test-sslv2-force-export-cipher.py”, line 9, in
    from tlsfuzzer.runner import Runner
    ImportError: No module named tlsfuzzer.runner

    any idea why?

  • Mark March 22, 2016, 12:20 pm

    If you get the ImportError: No module named tlsfuzzer.runner
    be sure to set/export PYTHONPATH=.

  • Mako April 19, 2016, 9:17 pm

    If you got this message:
    Traceback (most recent call last):
    File “scripts/test-sslv2-force-export-cipher.py”, line 9, in
    from tlsfuzzer.runner import Runner
    File “/home/Code/drown_attack/tlsfuzzer/tlsfuzzer/runner.py”, line 11, in
    from tlslite.constants import ContentType, HandshakeType, AlertLevel, \
    ImportError: cannot import name SSL2HandshakeType

    Try to re-make your links to the two dependent packages inside tlsfuzzer.
    For example if you have the three package (tlsfuzzer, escda, tlslite-ng) in the same dir level:
    $cd tlsfuzzer
    $ln -s ./../.tlslite-ng/tlslite/ tlslite
    $ls -s ./../.python-ecdsa/ecdsa/ ecdsa

    It works in my case. Hope to help you.

Leave a Comment