Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: ipa-4.13.1-3.el10 ------ Summary: Authenticated DoS in `otptoken-add` via unbounded OTP key decoding/re-encoding: a low-privilege authenticated user can submit an oversized `ipatokenotpkey` value that is Base32-decoded, re-encoded, and embedded into an enrollment URI without an effective size bound, causing excessive CPU and memory use in the IPA API worker handling the request. Requirements to exploit: Authenticated access to the IPA RPC interface as a user allowed to create self-managed OTP tokens, plus the ability to submit an oversized request body that is not rejected earlier by deployment-specific HTTP request-size controls. Component affected: `ipa-4.13.1-3.el10`, `ipaserver/plugins/otptoken.py`, `OTPTokenKey._convert_scalar()`, `otptoken_add.pre_callback()` Version affected: `ipa-4.13.1-3.el10` Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L - 5.3 (MEDIUM) AV:N - The issue is reachable over the network through the authenticated IPA RPC interface. AC:L - Exploitation requires only an oversized valid Base32 `ipatokenotpkey` value. PR:L - A regular authenticated user with self-service token creation rights is sufficient. UI:N - No victim interaction is required. S:U - The impact remains within the vulnerable IPA service. C:N - No confidentiality impact is established by the available evidence. I:N - No integrity impact is established by the available evidence. A:L - The request can consume worker CPU and memory and degrade service availability, but the available evidence does not establish consistent full-service outage across all deployments and some installations may reduce exposure with request-size limits. Impact: Important. Red Hat classifies flaws that allow remote users to cause denial of service as Important. This issue is reachable through a network-exposed authenticated endpoint, and the supplied materials show default self-managed token creation permissions for ordinary authenticated users. The demonstrated impact is availability degradation rather than confidentiality or integrity loss, and some deployments may reduce exposure with front-end request-size limits, but the established behavior still fits Important more closely than Moderate. Embargo: no Reason: The issue requires authenticated access, is limited to availability impact, and can often be reduced operationally with request-size controls or tighter token-management permissions, so embargo handling does not appear necessary. Acknowledgement: Aisle Research Vulnerability Details: Observed facts: `ipatokenotpkey` is declared without a size bound, `OTPTokenKey._convert_scalar()` decodes attacker-controlled Base32 input before returning to the normal bytes conversion path, and `otptoken_add.pre_callback()` then Base32-encodes the decoded bytes again and URL-encodes them into an `otpauth://` URI stored in request context. ```python OTPTokenKey('ipatokenotpkey?', cli_name='key', label=_('Key'), doc=_('Token secret (Base32; default: random)'), default_from=lambda: os.urandom(KEY_LENGTH), autofill=True, force server-side conversion normalizer=lambda x: x, flags=('no_display', 'no_update', 'no_search'), ), ... class OTPTokenKey(Bytes): """A binary password type specified in base32.""" password = True def _convert_scalar(self, value, index=None): if isinstance(value, (tuple, list)) and len(value) == 2: (p1, p2) = value if p1 != p2: raise PasswordMismatch(name=self.name) value = p1 if isinstance(value, unicode): try: value = base64.b32decode(value, True) except TypeError as e: raise ConversionError(name=self.name, error=str(e)) return super(OTPTokenKey, self)._convert_scalar(value) ... Build the URI parameters args = {} args['issuer'] = issuer args['secret'] = base64.b32encode(entry_attrs['ipatokenotpkey']) args['digits'] = entry_attrs['ipatokenotpdigits'] args['algorithm'] = entry_attrs['ipatokenotpalgorithm'].upper() if options['type'] == 'totp': args['period'] = entry_attrs['ipatokentotptimestep'] elif options['type'] == 'hotp': args['counter'] = entry_attrs['ipatokenhotpcounter'] Build the URI label = urllib.parse.quote(entry_attrs['ipatokenuniqueid']) parameters = urllib.parse.urlencode(args) uri = u'otpauth://%s/%s:%s?%s' % (options['type'], issuer, label, parameters) setattr(context, 'uri', uri) ``` The supplied materials also show a default ACI named `Users can create self-managed tokens`, so low-privilege authenticated users can reach this code path when token self-management is available as packaged. Reasonable inference: oversized valid Base32 input can force substantial CPU and memory work before the request completes, because the server decodes the supplied key, re-encodes it, URL-encodes the resulting parameters, and constructs a large enrollment URI in the same request path. Repeated or parallel requests can therefore degrade service availability. Open uncertainty: the available materials do not establish a universal crash threshold or prove that every supported deployment accepts arbitrarily large HTTP request bodies. Installations with strict front-end request-size limits may reduce or prevent exploitation before the vulnerable code path is reached. Steps to reproduce: 1. Authenticate to the IPA RPC interface as a normal user. 2. Create a JSON-RPC `otptoken_add` request with `type` set to `totp` and `ipatokenotpkey` set to a very large valid Base32 string, for example roughly 32 MiB of repeated `A`. 3. POST the request to `/ipa/session/json` with `Content-Type: application/json` using the authenticated session. 4. Observe CPU and memory spikes in the IPA API worker while the request is processed, specifically during Base32 decode, Base32 re-encode, parameter URL encoding, and `otpauth://` URI construction. 5. Repeat or parallelize the request to amplify the availability impact. Mitigation: Until a fix is available, enforce conservative HTTP request-body limits in front of `/ipa/session/json` so oversized payloads are rejected before IPA parameter conversion. If operationally acceptable, restrict self-managed token creation to trusted users and monitor or rate-limit repeated large authenticated requests. Proposed Fix: Reject oversized Base32 input before decode and enforce a decoded-size cap on `ipatokenotpkey`. ```diff diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py — a/ipaserver/plugins/otptoken.py +++ b/ipaserver/plugins/otptoken.py @@ KEY_LENGTH = 35 +MAX_OTPKEY_BYTES = 1024 +# Base32 expansion: 5 bytes -> 8 chars +MAX_OTPKEY_B32_CHARS = ((MAX_OTPKEY_BYTES + 4) // 5) * 8 @@ class OTPTokenKey(Bytes): @@ def _convert_scalar(self, value, index=None): @@ if isinstance(value, unicode): + if len(value) > MAX_OTPKEY_B32_CHARS: + raise ConversionError(name=self.name, error='OTP key is too large') try: value = base64.b32decode(value, True) except TypeError as e: raise ConversionError(name=self.name, error=str(e)) + if len(value) > MAX_OTPKEY_BYTES: + raise ConversionError(name=self.name, error='OTP key is too large') @@ OTPTokenKey('ipatokenotpkey?', cli_name='key', label=_('Key'), doc=_('Token secret (Base32; default: random)'), + maxlength=MAX_OTPKEY_BYTES, default_from=lambda: os.urandom(KEY_LENGTH), autofill=True, normalizer=lambda x: x, flags=('no_display', 'no_update', 'no_search'), ), ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use
Tracker filed for rhel-10.3: https://issues.redhat.com/browse/RHEL-188997