# RDP TLS Certificate Extraction

- **URL:** https://hackindex.io/services/rdp/enumeration/rdp-tls-certificate-extraction
- **Path:** RDP > Enumeration
- **Up:** [Enumeration](https://hackindex.io/services/rdp/enumeration.md)
- **Published:** 2026-01-04
- **Updated:** 2026-07-10

RDP over TLS often exposes a self-signed cert or an internal CA-issued cert. The subject and SANs frequently contain the real hostname and internal domain. That naming is immediately useful for DNS, SMB, LDAP, Kerberos, and spraying formats.

## RDP TLS certificate extraction with openssl

This pulls the first cert the server presents and prints only fields you’ll actually use.

```bash
openssl s_client -connect $TARGET_IP:$PORT -servername $TARGET_IP </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
```

What you expect:

- **subject**: usually includes CN with a hostname
- **issuer**: self-signed or internal CA name
- **notBefore/notAfter**: tells you if it’s stale or recently rolled

If you want SANs (often better than CN):

```bash
openssl s_client -connect $TARGET_IP:$PORT -servername $TARGET_IP </dev/null 2>/dev/null | openssl x509 -noout -text | grep -E 'Subject:|Issuer:|Not Before:|Not After :|DNS:'
# Subject: CN = WIN10-WS01.contoso.local
# Issuer: CN = CONTOSO-CA
# Not Before: Jan  2 08:11:20 2026 GMT
# Not After : Jan  2 08:11:20 2028 GMT
# DNS:win10-ws01.contoso.local, DNS:WIN10-WS01
#
```

## Dump the full chain

Use this when you want to identify the internal PKI (CA naming, intermediate CAs) or when the leaf cert is generic but the chain leaks org details.

```bash
openssl s_client -connect $TARGET_IP:$PORT -servername $TARGET_IP -showcerts </dev/null
```

What to do with it:

- If you see a non-public issuer and meaningful CNs, treat it as an internal CA deployment.
- If the issuer CN looks like a Windows CA hostname, you just got another internal naming pivot.

## How to use the certificate data

If you extract a hostname like `WIN10-WS01.contoso.local`:

- Set `$DOMAIN` to the internal domain you found.
- Add host mappings to avoid “name unknown” issues in tooling.

```bash
echo "$TARGET_IP win10-ws01.contoso.local win10-ws01" | sudo tee -a /etc/hosts
```

What this changes immediately:

- SMB/LDAP/Kerberos tooling becomes cleaner when you can use real hostnames and a consistent `$DOMAIN`.
- You can pivot into DNS enumeration using the discovered suffix, then expand hostlists for lateral checks.
- With domain context confirmed, proceed to credential attacks: see [RDP Brute Force and Password Spray.](https://hackindex.io/services/rdp/exploitation/brute-force-password-spray)

## If OpenSSL fails on older endpoints

Some older Windows builds only speak legacy TLS or present weak/old signature chains that modern OpenSSL rejects by default.

> [!WARNING]
> This is a legacy compatibility workaround. It relaxes OpenSSL’s security level so you can enumerate old RDP TLS stacks. Prefer fixing negotiation with a modern client when possible.

```bash
openssl s_client -connect $TARGET_IP:$PORT -servername $TARGET_IP -cipher 'DEFAULT:@SECLEVEL=0' </dev/null
```

If the cert suddenly appears after lowering security level, treat the endpoint as “old enough to be annoying” and validate with your RDP client early.

## Alternative: Nmap ssl-cert against RDP

If you want a quick, scriptable output without dealing with `s_client` noise:

```bash
nmap -Pn -p $PORT --script ssl-cert $TARGET_IP
```

What you get:

- Subject and issuer summary
- Validity window
- SANs when present

This is often enough to recover host/domain naming and decide your next pivot.

##

## References

- [Nmap ssl-cert NSE script](https://nmap.org/nsedoc/scripts/ssl-cert.html) - Pulls and summarizes X.509 certs from TLS services (works on RDP TLS)
- [OpenSSL s_client manual](https://docs.openssl.org/master/man1/openssl-s_client/) - TLS handshake client for certificate retrieval and debugging
- [OpenSSL x509 manual](https://docs.openssl.org/master/man1/openssl-x509/) - Parsing and extracting fields from X.509 certificates
