How to Programmatically Detect Vulnerable OpenSSL Versions (Including Heartbleed) Across Linux Distributions


2 views

The Heartbleed vulnerability (CVE-2014-0160) exposed a critical need for accurate OpenSSL version detection. While openssl version seems straightforward, we hit a major snag in practice:

$ openssl version -a
OpenSSL 1.0.1 14 Mar 2012
built on: Tue Jun  4 07:26:06 UTC 2013

The missing patch letter (e.g., 'g' in 1.0.1g) makes this output unreliable for security checks. Let's explore robust detection methods.

Here's a bash script that combines multiple verification approaches:

#!/bin/bash

# Method 1: Check build date (most reliable cross-distro indicator)
BUILD_DATE=$(openssl version -a | grep -i 'built on')
VULNERABLE_DATE="Mon Apr  7 20:33:29 UTC 2014"

if [[ "$BUILD_DATE" == *"$VULNERABLE_DATE"* ]]; then
    echo "[+] Secure build detected"
else
    echo "[-] Potentially vulnerable build"
fi

# Method 2: Package manager queries
if [ -f /etc/debian_version ]; then
    apt-cache policy openssl libssl1.0.0
elif [ -f /etc/redhat-release ]; then
    yum info openssl openssl-libs
fi

# Method 3: Shared library verification
ldd $(which openssl) | grep ssl

The discrepancy occurs because:

  • Distros often backport security fixes without changing the version string
  • The OpenSSL version macro (OPENSSL_VERSION_TEXT) doesn't always include patch letters
  • Shared libraries may report different versions than the CLI tool

For developers needing C/C++ integration:

#include 
#include 

int main() {
    printf("Compile-time version: %s\n", OPENSSL_VERSION_TEXT);
    
    const char *(*version_func)(int) = NULL;
    void *handle = dlopen("libssl.so", RTLD_LAZY);
    
    if (handle) {
        version_func = dlsym(handle, "SSLeay_version");
        if (version_func) {
            printf("Run-time version: %s\n", version_func(0));
        }
        dlclose(handle);
    }
    
    return 0;
}

When checking for Heartbleed fixes:

  1. Always check both openssl and libssl packages
  2. Verify the build date matches post-patch releases (April 2014+)
  3. Consider using the OpenSSL version API rather than CLI output
  4. Check for memory-resident old versions with: lsof -n | grep ssl | grep DEL

For Ubuntu/Debian:

apt-cache policy libssl1.0.0 | grep -E '1.0.1-[1-9]g'

For RHEL/CentOS:

rpm -qi openssl | grep -E 'Version.*1.0.1e-16'

For automated scanning across multiple servers, consider combining these methods with SSH command execution or configuration management tools.


When executing openssl version -a on Ubuntu 12.04 LTS with OpenSSL 1.0.1g, many administrators observe incomplete version information:

OpenSSL 1.0.1 14 Mar 2012
built on: Tue Jun  4 07:26:06 UTC 2013
platform: [...]

The critical version letter (a-g) is missing from the output, making Heartbleed vulnerability assessment difficult since only versions 1.0.1g and above are patched.

System Package Manager Queries

Debian/Ubuntu:

apt-cache policy openssl
apt-cache policy libssl1.0.0

RHEL/CentOS/Fedora:

rpm -qi openssl
yum info openssl openssl-libs

Direct Library Inspection

For systems where package managers aren't available:

strings /usr/lib/libssl.so | grep "^OpenSSL [0-9]"
strings /usr/lib64/libssl.so.* | grep "^OpenSSL [0-9]"

The patched versions have specific build timestamps:

# Safe versions will show:
built on: Mon Apr  7 20:33:29 UTC 2014

This corresponds to the Heartbleed patch release. Any earlier build date indicates vulnerability.

Identify if outdated libraries are still in use:

lsof -n | grep ssl | grep DEL
sudo netstat -plant | grep ':443'
sudo ss -plant | grep ':443'

Here's a POSIX-compliant shell script for version checking:

#!/bin/sh
check_openssl_version() {
    min_version="1.0.1g"
    current_version=$(openssl version | awk '{print $2}')
    
    printf '%s\n%s\n' "$min_version" "$current_version" | \
    sort -C -V -t '.' -k1,1 -k2,2 -k3,3
    if [ $? -eq 0 ]; then
        echo "VULNERABLE: OpenSSL $current_version"
        return 1
    else
        echo "SAFE: OpenSSL $current_version"
        return 0
    fi
}

check_openssl_version

The missing version letters occur because many distributions rebuild OpenSSL packages while maintaining the upstream version number. The actual patch status is better determined through:

  • Package changelogs (apt-get changelog openssl)
  • Distribution security advisories
  • Build timestamps

After upgrade, verify:

sudo ldd $(which openssl) | grep ssl
sudo service apache2 restart  # or appropriate web server
sudo openssl s_client -connect localhost:443 -tlsextdebug 2>&1 | grep heartbeat

The last command should show no heartbeat extension support in patched versions.