daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

700-pentesting-epp.md (19977B)


      1 ---
      2 title: "700 - Pentesting EPP"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/700-pentesting-epp.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/700-pentesting-epp.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # 700 - Pentesting EPP
     14 
     15 ## Basic Information
     16 
     17 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.<sup>[[4]](#references)</sup>
     18 
     19 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**.
     20 
     21 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.<sup>[[5]](#references)[[6]](#references)</sup>
     22 
     23 ### Pentest
     24 
     25 A good real-world starting point is [**HackCompute's research on vulnerable EPP implementations**](https://hackcompute.com/hacking-epp-servers/). 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**.<sup>[[1]](#references)</sup>
     26 
     27 ---
     28 
     29 ## Enumeration & Recon
     30 
     31 ### Initial network checks
     32 
     33 EPP servers commonly use hostnames such as `epp.<registry>`, `ote.<registry>`, `ot&e.<registry>`, `sandbox`, or `staging`.
     34 
     35 ```bash
     36 # TLS and certificate inspection
     37 nmap -sV -Pn -p700 --script ssl-cert,ssl-enum-ciphers <target>
     38 openssl s_client -connect <target>:700 -servername <target> -showcerts </dev/null
     39 ```
     40 
     41 Many registries require **mTLS** and will drop the session if no valid client certificate is presented. Still, it is worth checking whether:
     42 
     43 - the server leaks a greeting before enforcing registrar auth
     44 - OT&E / staging endpoints enforce weaker controls than production
     45 - a reverse proxy or HTTPS transport exists in front of the EPP service
     46 
     47 ### Grab the EPP greeting
     48 
     49 The greeting is the EPP equivalent of banner-grabbing. It tells you which **object URIs** and **extension namespaces** the server supports.
     50 
     51 ```python
     52 import socket
     53 import ssl
     54 import struct
     55 
     56 host = "target"
     57 message = b'<?xml version="1.0" encoding="UTF-8"?><epp xmlns="urn:ietf:params:xml:ns:epp-1.0"><hello/></epp>'
     58 
     59 def recv_exact(sock, size):
     60     data = b""
     61     while len(data) < size:
     62         chunk = sock.recv(size - len(data))
     63         if not chunk:
     64             raise ConnectionError("EPP connection closed")
     65         data += chunk
     66     return data
     67 
     68 def recv_epp(sock):
     69     header = recv_exact(sock, 4)
     70     size = struct.unpack("!I", header)[0]
     71     return recv_exact(sock, size - 4)
     72 
     73 context = ssl.create_default_context()
     74 with context.wrap_socket(socket.create_connection((host, 700)), server_hostname=host) as sock:
     75     print(recv_epp(sock).decode(errors="replace"))  # Server greeting
     76     sock.sendall(struct.pack("!I", len(message) + 4) + message)
     77     print(recv_epp(sock).decode(errors="replace"))
     78 ```
     79 
     80 From the greeting, pay attention to namespaces such as:
     81 
     82 - `domain`, `host`, `contact`
     83 - `secDNS` --> DNSSEC DS / key-data management
     84 - `rgp` --> restore / redemption flows
     85 - `launch`, `fee`, `ttl`, proprietary namespaces --> custom business logic / extra parser surface
     86 - `loginSec` --> login-security extension
     87 - `changePoll`, `maintenance` --> out-of-band workflow visibility
     88 
     89 If the server advertises a lot of extensions, the parser and authorization surface is usually much larger than the base RFCs suggest.
     90 
     91 ### Check for EPP over HTTPS
     92 
     93 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.<sup>[[6]](#references)</sup>
     94 
     95 ```bash
     96 curl -isk https://<target>/ -H 'Accept: application/epp+xml'
     97 ```
     98 
     99 If HTTPS works, test it like an authenticated/stateful API in addition to classic EPP:
    100 
    101 - cookie fixation / session mix-up behind load balancers
    102 - path confusion (`/`, `/epp`, `/api/epp`, `/registry/epp`)
    103 - reverse-proxy auth mistakes
    104 - accidental caching or logging of XML bodies and transfer credentials
    105 
    106 ### Look for forgotten OT&E / registrar onboarding infrastructure
    107 
    108 Public registry documentation is often gold. For example, some registrar manuals openly document:
    109 
    110 - production EPP endpoints
    111 - OT&E / certification endpoints
    112 - whether OT&E is IP-restricted or not
    113 - registrar consoles, WHOIS test services, and onboarding workflows
    114 
    115 That matters because **test environments commonly share code paths with production** while having weaker IP allowlists, reused credentials, weaker certificates, or lower scrutiny.
    116 
    117 ### Authentication stack to map
    118 
    119 Real deployments often layer several controls:
    120 
    121 - **client certificate**
    122 - **source IP allowlist**
    123 - **EPP username/password**
    124 - optional registrar web panel / reseller console that ultimately issues EPP actions
    125 
    126 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.
    127 
    128 ### Open-source clients useful for testing
    129 
    130 - **[domainr/epp](https://github.com/domainr/epp)** / **[domainr/epp2](https://github.com/domainr/epp2)** – lightweight Go clients that are easy to instrument for fuzzing and custom namespaces.
    131 - **[CZ-NIC/fred-client](https://github.com/CZ-NIC/fred-client)** – Python CLI/API for FRED-based registries.
    132 - **[getnamingo/epp-client](https://github.com/getnamingo/epp-client)** – PHP client with broad registry support, including EPP-over-HTTPS support in current releases.
    133 - **[metaregistrar/php-epp-client](https://github.com/metaregistrar/php-epp-client)** – mature object-oriented PHP client with support for many registry-specific extensions.
    134 
    135 ---
    136 
    137 ## High-Value EPP Operations
    138 
    139 If you obtain registrar-level access, these operations usually have the highest offensive value:
    140 
    141 | Operation | Why it matters |
    142 | --- | --- |
    143 | `domain:update` | Change nameservers, contacts, statuses, or `authInfo` |
    144 | `domain:transfer` | Move the domain to another registrar or interfere with approval flows |
    145 | `domain:info` | Reveals object and transfer state; authorization material is subject to object mapping and server policy |
    146 | `secDNS:update` | Add/remove/replace DS or key data to break validation or control DNSSEC state |
    147 | `poll` | Observe asynchronous events: transfer approvals, registry actions, out-of-band changes |
    148 
    149 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.
    150 
    151 ---
    152 
    153 ## Common Weaknesses & Attack Surface
    154 
    155 ### XML parser bugs (XXE, SSRF, local file disclosure)
    156 
    157 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.<sup>[[1]](#references)</sup>
    158 
    159 Basic test payload:
    160 
    161 ```xml
    162 <?xml version="1.0"?>
    163 <!DOCTYPE x [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
    164 <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
    165   <command>
    166     <check>
    167       <domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
    168         <domain:name>&xxe;</domain:name>
    169       </domain:check>
    170     </check>
    171   </command>
    172 </epp>
    173 ```
    174 
    175 Besides plain file read, test for:
    176 
    177 - **SSRF** to metadata/internal services
    178 - **external DTD fetches** for blind callbacks
    179 - entity expansion reflected through schema or validation errors
    180 - parser differences between **production** and **OT&E** stacks
    181 - XML handling in **registrar-side portals** that transform user input into EPP XML
    182 
    183 ### mTLS and transport mistakes
    184 
    185 Common real-world failures include:
    186 
    187 1. **Anonymous TLS is accepted**, and only the EPP `login` is enforced.
    188 2. A **reverse proxy terminates TLS**, but the backend does not require or correctly forward the verified client-certificate identity.
    189 3. A registrar client **does not validate the registry certificate** correctly, enabling credential theft or on-path interception of the EPP `login`.
    190 4. The service lacks **IP allowlists, connection quotas, or rate limits**, making low-and-slow password spraying practical.
    191 
    192 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.
    193 
    194 ### EPP-over-HTTPS session handling
    195 
    196 Where the registry exposes EPP over HTTPS, add standard web-session testing on top of EPP semantics:
    197 
    198 - **session fixation**, especially when a pre-authentication cookie survives login
    199 - **session replay** from another IP or client
    200 - weak or predictable session identifiers
    201 - loss of mTLS guarantees at the HTTPS gateway
    202 - caching or logging of XML bodies and transfer credentials
    203 
    204 The HTTP session and reverse proxy become part of the EPP security boundary, so ordinary cookie or proxy bugs can become registry-control bugs.
    205 
    206 ### Legacy password model and the `loginSec` extension
    207 
    208 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.<sup>[[4]](#references)[[7]](#references)</sup>
    209 
    210 When testing authenticated access, check whether the registry still behaves like an old deployment:
    211 
    212 - short shared passwords only
    213 - no password rotation hints
    214 - no visibility into expiring client certificates
    215 - no telemetry for repeated failed logins or insecure TLS/cipher negotiation
    216 
    217 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.
    218 
    219 ### `authInfo` / EPP code abuse and transfer workflows
    220 
    221 `authInfo` (also called EPP code / transfer code / Auth-Info code) is one of the most valuable secrets in the domain lifecycle.
    222 
    223 The important offensive detail is that **the protocol and policy surface around transfers is still large**:
    224 
    225 - EPP domain objects support `authInfo`
    226 - ICANN transfer policy still requires registrars to provide the AuthInfo code and remove `ClientTransferProhibited` within specific conditions/time limits
    227 - [RFC 9154](https://datatracker.ietf.org/doc/html/rfc9154) exists because long-lived, stored, reusable transfer secrets are dangerous<sup>[[2]](#references)</sup>
    228 
    229 Practical checks:
    230 
    231 - Can a low-privilege user, reseller, or support role **view or reset** `authInfo`?
    232 - Does a registrar panel/API return a **static** transfer code that rarely changes?
    233 - Is `authInfo` emailed, ticketed, logged, or stored in CRM/internal notes?
    234 - Can you **unlock** a domain or fetch its EPP code through a weaker path than the one required to edit nameservers/contacts?
    235 - Do internal APIs mirror `domain:info` responses containing authorization data to users that should not see it?
    236 - Can a transfer be raced against manual review or asynchronous approval messages?
    237 
    238 Example transfer request using leaked `authInfo`:
    239 
    240 ```xml
    241 <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
    242   <command>
    243     <transfer op="request">
    244       <domain:transfer xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
    245         <domain:name>victim.tld</domain:name>
    246         <domain:authInfo><domain:pw>AUTH-CODE</domain:pw></domain:authInfo>
    247       </domain:transfer>
    248     </transfer>
    249   </command>
    250 </epp>
    251 ```
    252 
    253 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.<sup>[[2]](#references)</sup>
    254 
    255 ### DNSSEC / `secDNS` abuse
    256 
    257 Once you have EPP access, do not stop at nameserver changes. Many operators forget that EPP also controls **DNSSEC state**.
    258 
    259 With the EPP `secDNS` extension, a registrar can add or remove **DS records** and key data. A privileged attacker may therefore be able to:<sup>[[8]](#references)</sup>
    260 
    261 - remove DS material to intentionally break validation during takeover
    262 - replace DS/key data to match attacker-controlled signing keys
    263 - combine nameserver and DNSSEC changes in one workflow to make recovery slower and more error-prone
    264 
    265 Minimal example of removing all existing DNSSEC material and adding attacker-controlled DS data:
    266 
    267 ```xml
    268 <extension xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1">
    269   <secDNS:update>
    270     <secDNS:rem><secDNS:all>true</secDNS:all></secDNS:rem>
    271     <secDNS:add>
    272       <secDNS:dsData>
    273         <secDNS:keyTag>31337</secDNS:keyTag><secDNS:alg>13</secDNS:alg>
    274         <secDNS:digestType>2</secDNS:digestType><secDNS:digest>DEADBEEF</secDNS:digest>
    275       </secDNS:dsData>
    276     </secDNS:add>
    277   </secDNS:update>
    278 </extension>
    279 ```
    280 
    281 ### Poll queue, change poll, and maintenance events
    282 
    283 Modern EPP deployments increasingly rely on asynchronous workflows:
    284 
    285 - `poll` for queued messages
    286 - **Change Poll** for out-of-band object changes.<sup>[[9]](#references)</sup>
    287 - **Registry Maintenance Notification** for planned and emergency maintenance.<sup>[[10]](#references)</sup>
    288 
    289 These are valuable during an assessment because they often reveal:
    290 
    291 - transfers initiated outside your current session
    292 - support/operator actions not initiated via EPP
    293 - UDRP/court/policy-driven changes
    294 - maintenance windows and secondary systems
    295 
    296 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.
    297 
    298 ---
    299 
    300 ## Registry-Side Lifecycle Flaws
    301 
    302 Registry abuse is not limited to parser and authentication bugs. Research presented at USENIX Security 2025 identified lifecycle and delegation inconsistencies with security impact:<sup>[[3]](#references)</sup>
    303 
    304 1. **Twin domain names for IDNs**: defensive auto-created sibling objects can leave a related internationalized-domain variant available for registration.
    305 2. **Stale glue or siloed host-object management**: a registry may continue delegating domains through expired or attacker-controlled nameserver objects.
    306 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.
    307 
    308 Useful external checks include comparing registry or RDAP lifecycle data with the live delegation:
    309 
    310 ```bash
    311 dig +trace victim.tld NS
    312 dig +short NS victim.tld
    313 ```
    314 
    315 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](/hacktricks/pentesting-web/domain-subdomain-takeover), but the flaw is in the registry lifecycle and delegation pipeline.
    316 
    317 ---
    318 
    319 ## Practical Offensive Checks
    320 
    321 1. **Find every endpoint**: production, OT&E, reseller, registrar console, API gateway, docs, and WHOIS/RDAP references.
    322 2. **Enumerate greeting namespaces** and map which flows exist: transfer, DNSSEC, poll, launch, fee, maintenance.
    323 3. **Compare prod vs OT&E**: cert policy, source-IP restrictions, login behavior, extension availability, error handling.
    324 4. **Hunt for transfer-secret exposure** in registrar UIs, APIs, ticketing, logs, exports, and support workflows.
    325 5. **Test authorization asymmetry**: can you unlock / fetch EPP code / transfer more easily than you can edit nameservers?
    326 6. **Abuse post-compromise EPP breadth**: nameservers, statuses, `authInfo`, DS records, contact changes, and poll queue visibility.
    327 7. **For HTTPS transports**, test cookie/session behavior and proxy-induced bugs exactly like a high-value stateful XML API.
    328 8. **Compare lifecycle state with DNS delegation** to find stale glue, relic domains, and inconsistent IDN sibling handling.
    329 
    330 ---
    331 
    332 ## Attack Path: From Recon to Domain / TLD Hijack
    333 
    334 1. Discover production or OT&E EPP infrastructure via docs, certificates, registrar portals, or related services.
    335 2. Enumerate the greeting to learn supported namespaces and high-value operations.
    336 3. Obtain registrar capability by exploiting XML parsing, a registrar control-plane bug, stolen client certificate, leaked EPP credentials, or exposed `authInfo` workflows.
    337 4. Change `hostObj` / nameserver data, rotate `authInfo`, submit transfer operations, or alter DNSSEC material through `secDNS:update`.
    338 5. Abuse stale glue or relic-domain behavior to retain or regain control across lifecycle transitions.
    339 6. Use `poll` responses and asynchronous workflow artefacts to monitor completion and race defenders.
    340 
    341 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**.
    342 
    343 ---
    344 
    345 ## Defensive Measures & Hardening
    346 
    347 Keep this short from an offensive perspective, but these are the controls that most reduce attacker options:
    348 
    349 - enforce **mTLS + source-IP restrictions + strong/passphrase-based login security**
    350 - treat **OT&E/staging** as production-grade from an auth and monitoring perspective
    351 - implement **short-lived, one-time, hashed `authInfo`** workflows
    352 - alert on **nameserver, transfer, and DNSSEC** changes together, not separately
    353 - consume and review **poll / change-poll / maintenance** events centrally
    354 - continuously reconcile registration state, host objects, and live **NS/glue delegation**
    355 
    356 ## References
    357 
    358 - [1] [HackCompute - can I speak to your manager? hacking root EPP servers to take control of zones](https://hackcompute.com/hacking-epp-servers/)
    359 - [2] [RFC 9154 - Extensible Provisioning Protocol (EPP) Secure Authorization Information for Transfer](https://datatracker.ietf.org/doc/html/rfc9154)
    360 - [3] [USENIX Security 2025 - Misty Registry: An Empirical Study of Flawed Domain Registry Operation](https://www.usenix.org/conference/usenixsecurity25/presentation/zhang-mingming)
    361 - [4] [RFC 5730 – Extensible Provisioning Protocol (EPP)](https://www.rfc-editor.org/rfc/rfc5730)
    362 - [5] [RFC 5734 – EPP Transport over TCP](https://www.rfc-editor.org/rfc/rfc5734)
    363 - [6] [IETF Internet-Draft – EPP Transport over HTTPS](https://datatracker.ietf.org/doc/draft-ietf-regext-epp-https/)
    364 - [7] [RFC 8807 – Login Security Extension for EPP](https://www.rfc-editor.org/rfc/rfc8807)
    365 - [8] [RFC 5910 – Domain Name System Security Extensions Mapping for EPP](https://www.rfc-editor.org/rfc/rfc5910)
    366 - [9] [RFC 8590 – Change Poll Extension for EPP](https://www.rfc-editor.org/rfc/rfc8590)
    367 - [10] [RFC 9167 – Registry Maintenance Notification for EPP](https://www.rfc-editor.org/rfc/rfc9167)