// HackTricks · Network Services

700 - Pentesting EPP

700 - Pentesting EPP

Basic Information

The Extensible Provisioning Protocol (EPP) is an XML-based protocol used by registries and registrars to provision objects such as domains, hosts, and contacts. Extensions add functions such as DNSSEC management and lifecycle notifications.[4]

In practice, this is one of the most sensitive services in a TLD environment: if you can operate EPP as a registrar or abuse a registrar-facing control plane that proxies EPP actions, you can usually change nameservers, rotate transfer credentials, alter DNSSEC state, or transfer domains away.

The standardized transport is TLS over TCP on port 700/tcp. Deployments commonly layer certificate-based client authentication, source-IP restrictions, and an EPP login username/password. Each data unit begins with a four-byte big-endian total length (including the length field), followed by the XML document. Current IETF work also defines EPP over HTTPS, so assessments should check documented web gateways rather than assume the surface is limited to raw TCP/700.[5][6]

Pentest

A good real-world starting point is HackCompute’s research on vulnerable EPP implementations. They found XML parser abuse (XXE) and chained it into local file disclosure against real registry software, showing how an EPP bug can become domain or even TLD-level compromise.[1]


Enumeration & Recon

Initial network checks

EPP servers commonly use hostnames such as epp.<registry>, ote.<registry>, ot&e.<registry>, sandbox, or staging.

# TLS and certificate inspection
nmap -sV -Pn -p700 --script ssl-cert,ssl-enum-ciphers <target>
openssl s_client -connect <target>:700 -servername <target> -showcerts </dev/null

Many registries require mTLS and will drop the session if no valid client certificate is presented. Still, it is worth checking whether:

  • the server leaks a greeting before enforcing registrar auth
  • OT&E / staging endpoints enforce weaker controls than production
  • a reverse proxy or HTTPS transport exists in front of the EPP service

Grab the EPP greeting

The greeting is the EPP equivalent of banner-grabbing. It tells you which object URIs and extension namespaces the server supports.

import socket
import ssl
import struct

host = "target"
message = b'<?xml version="1.0" encoding="UTF-8"?><epp xmlns="urn:ietf:params:xml:ns:epp-1.0"><hello/></epp>'

def recv_exact(sock, size):
    data = b""
    while len(data) < size:
        chunk = sock.recv(size - len(data))
        if not chunk:
            raise ConnectionError("EPP connection closed")
        data += chunk
    return data

def recv_epp(sock):
    header = recv_exact(sock, 4)
    size = struct.unpack("!I", header)[0]
    return recv_exact(sock, size - 4)

context = ssl.create_default_context()
with context.wrap_socket(socket.create_connection((host, 700)), server_hostname=host) as sock:
    print(recv_epp(sock).decode(errors="replace"))  # Server greeting
    sock.sendall(struct.pack("!I", len(message) + 4) + message)
    print(recv_epp(sock).decode(errors="replace"))

From the greeting, pay attention to namespaces such as:

  • domain, host, contact
  • secDNS —> DNSSEC DS / key-data management
  • rgp —> restore / redemption flows
  • launch, fee, ttl, proprietary namespaces —> custom business logic / extra parser surface
  • loginSec —> login-security extension
  • changePoll, maintenance —> out-of-band workflow visibility

If the server advertises a lot of extensions, the parser and authorization surface is usually much larger than the base RFCs suggest.

Check for EPP over HTTPS

The current EPP-over-HTTPS Internet-Draft maps connection initiation/greeting retrieval to an HTTP GET and commands to HTTP POST, with state associated through a server cookie. Because this remains a draft, confirm behavior against the exact implementation and draft version. Indicators include application/epp+xml, Set-Cookie, and explicit cache controls.[6]

curl -isk https://<target>/ -H 'Accept: application/epp+xml'

If HTTPS works, test it like an authenticated/stateful API in addition to classic EPP:

  • cookie fixation / session mix-up behind load balancers
  • path confusion (/, /epp, /api/epp, /registry/epp)
  • reverse-proxy auth mistakes
  • accidental caching or logging of XML bodies and transfer credentials

Look for forgotten OT&E / registrar onboarding infrastructure

Public registry documentation is often gold. For example, some registrar manuals openly document:

  • production EPP endpoints
  • OT&E / certification endpoints
  • whether OT&E is IP-restricted or not
  • registrar consoles, WHOIS test services, and onboarding workflows

That matters because test environments commonly share code paths with production while having weaker IP allowlists, reused credentials, weaker certificates, or lower scrutiny.

Authentication stack to map

Real deployments often layer several controls:

  • client certificate
  • source IP allowlist
  • EPP username/password
  • optional registrar web panel / reseller console that ultimately issues EPP actions

This is important during an assessment because you do not always need direct socket-level EPP access. Compromising a registrar console, support workflow, internal API, or an automation worker that holds the client certificate may be enough.

Open-source clients useful for testing


High-Value EPP Operations

If you obtain registrar-level access, these operations usually have the highest offensive value:

OperationWhy it matters
domain:updateChange nameservers, contacts, statuses, or authInfo
domain:transferMove the domain to another registrar or interfere with approval flows
domain:infoReveals object and transfer state; authorization material is subject to object mapping and server policy
secDNS:updateAdd/remove/replace DS or key data to break validation or control DNSSEC state
pollObserve asynchronous events: transfer approvals, registry actions, out-of-band changes

A lot of real compromises happen around these commands rather than in the XML parser itself: panel/API auth bugs, support workflows, leaked transfer codes, stale OT&E credentials, or weak separation between resellers and parent registrar accounts.


Common Weaknesses & Attack Surface

XML parser bugs (XXE, SSRF, local file disclosure)

EPP is XML, so the classic parser bug class is still relevant. Some implementations parse and schema-validate XML before processing login, allowing malformed commands to reach the parser unauthenticated. The HackCompute research showed how XXE in real EPP implementations could be chained into local file disclosure and potentially much wider registry compromise.[1]

Basic test payload:

<?xml version="1.0"?>
<!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <check>
      <domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>&xxe;</domain:name>
      </domain:check>
    </check>
  </command>
</epp>

Besides plain file read, test for:

  • SSRF to metadata/internal services
  • external DTD fetches for blind callbacks
  • entity expansion reflected through schema or validation errors
  • parser differences between production and OT&E stacks
  • XML handling in registrar-side portals that transform user input into EPP XML

mTLS and transport mistakes

Common real-world failures include:

  1. Anonymous TLS is accepted, and only the EPP login is enforced.
  2. A reverse proxy terminates TLS, but the backend does not require or correctly forward the verified client-certificate identity.
  3. A registrar client does not validate the registry certificate correctly, enabling credential theft or on-path interception of the EPP login.
  4. The service lacks IP allowlists, connection quotas, or rate limits, making low-and-slow password spraying practical.

Because TCP EPP uses a length prefix, custom gateways and protocol relays are also worth fuzzing with truncated, oversized, or desynchronized frame lengths before the XML parser is reached.

EPP-over-HTTPS session handling

Where the registry exposes EPP over HTTPS, add standard web-session testing on top of EPP semantics:

  • session fixation, especially when a pre-authentication cookie survives login
  • session replay from another IP or client
  • weak or predictable session identifiers
  • loss of mTLS guarantees at the HTTPS gateway
  • caching or logging of XML bodies and transfer credentials

The HTTP session and reverse proxy become part of the EPP security boundary, so ordinary cookie or proxy bugs can become registry-control bugs.

Legacy password model and the loginSec extension

Base EPP constrains pw/newPW to 6–16 characters. RFC 8807 introduced the Login Security Extension, which can carry longer server-policy-controlled passwords and machine-readable security events.[4][7]

When testing authenticated access, check whether the registry still behaves like an old deployment:

  • short shared passwords only
  • no password rotation hints
  • no visibility into expiring client certificates
  • no telemetry for repeated failed logins or insecure TLS/cipher negotiation

If loginSec is enabled, a successful login can return structured warnings such as expiring passwords/certificates, insecure TLS versions/ciphers, or high failed-login counts. That is useful both for offensive situational awareness and for identifying weak operational hygiene.

authInfo / EPP code abuse and transfer workflows

authInfo (also called EPP code / transfer code / Auth-Info code) is one of the most valuable secrets in the domain lifecycle.

The important offensive detail is that the protocol and policy surface around transfers is still large:

  • EPP domain objects support authInfo
  • ICANN transfer policy still requires registrars to provide the AuthInfo code and remove ClientTransferProhibited within specific conditions/time limits
  • RFC 9154 exists because long-lived, stored, reusable transfer secrets are dangerous[2]

Practical checks:

  • Can a low-privilege user, reseller, or support role view or reset authInfo?
  • Does a registrar panel/API return a static transfer code that rarely changes?
  • Is authInfo emailed, ticketed, logged, or stored in CRM/internal notes?
  • Can you unlock a domain or fetch its EPP code through a weaker path than the one required to edit nameservers/contacts?
  • Do internal APIs mirror domain:info responses containing authorization data to users that should not see it?
  • Can a transfer be raced against manual review or asynchronous approval messages?

Example transfer request using leaked authInfo:

<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
  <command>
    <transfer op="request">
      <domain:transfer xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
        <domain:name>victim.tld</domain:name>
        <domain:authInfo><domain:pw>AUTH-CODE</domain:pw></domain:authInfo>
      </domain:transfer>
    </transfer>
  </command>
</epp>

The secure model from RFC 9154 is: strong random authInfo, short-lived, not stored by the client, hashed at the server, not logged, and automatically unset after successful transfer. Anything materially weaker is worth digging into.[2]

DNSSEC / secDNS abuse

Once you have EPP access, do not stop at nameserver changes. Many operators forget that EPP also controls DNSSEC state.

With the EPP secDNS extension, a registrar can add or remove DS records and key data. A privileged attacker may therefore be able to:[8]

  • remove DS material to intentionally break validation during takeover
  • replace DS/key data to match attacker-controlled signing keys
  • combine nameserver and DNSSEC changes in one workflow to make recovery slower and more error-prone

Minimal example of removing all existing DNSSEC material and adding attacker-controlled DS data:

<extension xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
  <secDNS:update>
    <secDNS:rem><secDNS:all>true</secDNS:all></secDNS:rem>
    <secDNS:add>
      <secDNS:dsData>
        <secDNS:keyTag>31337</secDNS:keyTag><secDNS:alg>13</secDNS:alg>
        <secDNS:digestType>2</secDNS:digestType><secDNS:digest>DEADBEEF</secDNS:digest>
      </secDNS:dsData>
    </secDNS:add>
  </secDNS:update>
</extension>

Poll queue, change poll, and maintenance events

Modern EPP deployments increasingly rely on asynchronous workflows:

  • poll for queued messages
  • Change Poll for out-of-band object changes.[9]
  • Registry Maintenance Notification for planned and emergency maintenance.[10]

These are valuable during an assessment because they often reveal:

  • transfers initiated outside your current session
  • support/operator actions not initiated via EPP
  • UDRP/court/policy-driven changes
  • maintenance windows and secondary systems

If a registrar mirrors these messages into email, webhooks, dashboards, or reseller portals, test those integrations too. A weak internal consumer can become the easier compromise path than raw EPP itself.


Registry-Side Lifecycle Flaws

Registry abuse is not limited to parser and authentication bugs. Research presented at USENIX Security 2025 identified lifecycle and delegation inconsistencies with security impact:[3]

  1. Twin domain names for IDNs: defensive auto-created sibling objects can leave a related internationalized-domain variant available for registration.
  2. Stale glue or siloed host-object management: a registry may continue delegating domains through expired or attacker-controlled nameserver objects.
  3. Relic domains: a domain becomes available again while the TLD zone retains old NS or glue delegation, allowing the next registrant to inherit dangerous state.

Useful external checks include comparing registry or RDAP lifecycle data with the live delegation:

dig +trace victim.tld NS
dig +short NS victim.tld

If a domain is available or recently dropped but the TLD still delegates old NS or glue records, re-registration can become a registry-level hijack primitive. The downstream effect resembles domain or subdomain takeover, but the flaw is in the registry lifecycle and delegation pipeline.


Practical Offensive Checks

  1. Find every endpoint: production, OT&E, reseller, registrar console, API gateway, docs, and WHOIS/RDAP references.
  2. Enumerate greeting namespaces and map which flows exist: transfer, DNSSEC, poll, launch, fee, maintenance.
  3. Compare prod vs OT&E: cert policy, source-IP restrictions, login behavior, extension availability, error handling.
  4. Hunt for transfer-secret exposure in registrar UIs, APIs, ticketing, logs, exports, and support workflows.
  5. Test authorization asymmetry: can you unlock / fetch EPP code / transfer more easily than you can edit nameservers?
  6. Abuse post-compromise EPP breadth: nameservers, statuses, authInfo, DS records, contact changes, and poll queue visibility.
  7. For HTTPS transports, test cookie/session behavior and proxy-induced bugs exactly like a high-value stateful XML API.
  8. Compare lifecycle state with DNS delegation to find stale glue, relic domains, and inconsistent IDN sibling handling.

Attack Path: From Recon to Domain / TLD Hijack

  1. Discover production or OT&E EPP infrastructure via docs, certificates, registrar portals, or related services.
  2. Enumerate the greeting to learn supported namespaces and high-value operations.
  3. Obtain registrar capability by exploiting XML parsing, a registrar control-plane bug, stolen client certificate, leaked EPP credentials, or exposed authInfo workflows.
  4. Change hostObj / nameserver data, rotate authInfo, submit transfer operations, or alter DNSSEC material through secDNS:update.
  5. Abuse stale glue or relic-domain behavior to retain or regain control across lifecycle transitions.
  6. Use poll responses and asynchronous workflow artefacts to monitor completion and race defenders.

For a single domain, this usually means DNS takeover, certificate issuance opportunity, and email interception. For a registry-side compromise, the blast radius can become every domain sponsored by that registrar or even the full TLD.


Defensive Measures & Hardening

Keep this short from an offensive perspective, but these are the controls that most reduce attacker options:

  • enforce mTLS + source-IP restrictions + strong/passphrase-based login security
  • treat OT&E/staging as production-grade from an auth and monitoring perspective
  • implement short-lived, one-time, hashed authInfo workflows
  • alert on nameserver, transfer, and DNSSEC changes together, not separately
  • consume and review poll / change-poll / maintenance events centrally
  • continuously reconcile registration state, host objects, and live NS/glue delegation

References