Only the first Alt-Svc ALPN negotiation is verified
Categories
(Core :: Networking, defect, P1)
Tracking
()
People
(Reporter: pspaul95+bugzilla, Assigned: valentin)
References
Details
(Keywords: csectype-sop, reporter-external, sec-moderate, Whiteboard: [client-bounty-form][necko-triaged][necko-priority-queue][adv-main134+][adv-ESR128.6+])
Attachments
(7 files)
|
7.78 KB,
application/zip
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
tjr
:
sec-approval+
|
Details | Review |
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
|
1.86 KB,
text/plain
|
Details | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-esr128+
|
Details | Review |
|
187 bytes,
text/plain
|
Details |
Version: Firefox 131.0.3 (64-bit)
OS: Manjaro Linux 24.1.1
How was this issue discovered?
Manual testing. I was researching cross-protocol attacks using the Alt-Svc header when I found this bypass.
General Description:
The Alt-Svc spec's section 2.4 (https://httpwg.org/specs/rfc7838.html#switching) mandates that the browser verifies that the alternative service negotiates the correct protocol, for example via ALPN:
If the connection to the alternative service does not negotiate the expected protocol (for example, ALPN fails to negotiate h2, or an Upgrade request to h2c is not accepted), the connection to the alternative service MUST be considered to have failed.
Firefox only verifies this for the first connection but not for subsequent ones. Therefore, a Man-in-the-Middle attacker can bypass the ALPN check by forwarding the first connection to a valid server, closing the connection after some time, and forwarding all subsequent requests to a different server.
The PoC demonstrates this by running three TLS servers, all using the same certificate:
- HTTP/1.1 on port
:8443(ALPN offershttp1.1) - HTTP/2 on port
:8444(ALPN offersh2) - Plain TLS on port
:8445(ALPN list is empty)
Firefox should never use the alternative service h2=":8445" because ALPN will not negotiate h2. However, by forwarding the first request to :8444, which correctly negotiates h2, Firefox can be tricked into trusting all later connections.
Steps to reproduce:
- Start the PoC:
node server.js - Add
127.0.0.1 foo.example.comto your/etc/hostsfile - Visit
https://foo.example.com:8443/?alt-svc=:1337in Firefox - Accept the self-signed certificate warning (or replace
privkey.pemandfullchain.pemwith valid certificates before step 1) - Now the following should happen:
- The page will first be served via HTTP/1.1 over TLS from
:8443, delivering theAlt-Svc: h2=":1337"header - After 1 second, the page refreshes, causing the browser to make the first connection to the attacker's alternative service on
:1337 - The attacker forwards this first request to the legitimate HTTP/2 server on
:8444 - The new page loads, showing that it was loaded via HTTP/2
- The attacker now closes the forwarded connection between the browser and the HTTP/2 server
- The page then refreshes again, causing the browser to open a new connection to the attacker on
:1337 - The attacker now forwards the request to the invalid TLS server at
:8445 - The page loads, showing that it was loaded from
:8445, which shouldn't happen
- The page will first be served via HTTP/1.1 over TLS from
The PoC script's output should demonstrate the same:
[h1] GET /?alt-svc=:1337
[attacker] Forwarding to h2 (:8444)
[h1] GET /favicon.ico
[h2] GET /?refresh
[attacker] Terminating first connection
[attacker] Forwarding to plain (:8445)
[plain] Got connection
[plain] Got data: GET / HTTP/1.1
[plain] Got data: Host: foo.example.com:8443
[plain] Got data: User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:131.0) Gecko/20100101 Firefox/131.0
...
I also recorded a demo of the PoC, I hope you enjoy it ;)
Root cause analysis:
I'm not very familiar with the Firefox code base, but it looks like TRRServiceChannel::BeginConnect() is consulting the Alt-Svc cache here: https://searchfox.org/mozilla-central/rev/387f3edbef37d31b2e91fb0812c74b54729e86ff/netwerk/protocol/http/TRRServiceChannel.cpp#405-407
If there's a matching entry, it means that the alternative service was previously validated, and Firefox connects to the mConnectionInfo from the cache entry instead of the original one.
I think the problem here is that the Alt-Svc cache holds the validation state. To me, the spec sounds like each new TLS connection needs to do the validation individually to prevent a Man-in-the-Middle attacker from switching the destination server at some point.
Comment 1•1 year ago
|
||
Looks like the attachment did not make it through yet. Submitting for pspaul.
Updated•1 year ago
|
| Assignee | ||
Comment 3•1 year ago
|
||
Updated•1 year ago
|
| Assignee | ||
Updated•1 year ago
|
| Assignee | ||
Updated•1 year ago
|
Updated•1 year ago
|
| Assignee | ||
Comment 4•1 year ago
|
||
| Assignee | ||
Comment 5•1 year ago
|
||
Comment on attachment 9435935 [details]
Bug 1929156 - Check negotiated ALPN matches altSvc protocol r=#necko
Security Approval Request
- How easily could an exploit be constructed based on the patch?: Relatively easily.
- Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: Yes
- Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?: all
- If not all supported branches, which bug introduced the flaw?: None
- Do you have backports for the affected branches?: Yes
- If not, how different, hard to create, and risky will they be?: Applies cleanly to all branches
- How likely is this patch to cause regressions; how much testing does it need?: Unlikely to cause regressions.
- Is the patch ready to land after security approval is given?: Yes
- Is Android affected?: Yes
Comment 6•1 year ago
|
||
Do I understand correctly that exploiting this would require an unusual server configuration that is likely extremely uncommon?
| Assignee | ||
Comment 7•1 year ago
|
||
(In reply to Tom Ritter [:tjr] from comment #6)
Do I understand correctly that exploiting this would require an unusual server configuration that is likely extremely uncommon?
Yes, the original server needs to provide an alt-svc directing the browser to a port it doesn't control. And even so, TLS is still required, so I'm not sure how much damage the attacker could do.
Comment 8•1 year ago
|
||
Comment on attachment 9435935 [details]
Bug 1929156 - Check negotiated ALPN matches altSvc protocol r=#necko
Approved to land and uplift
Updated•1 year ago
|
Comment 10•1 year ago
|
||
| Assignee | ||
Comment 11•1 year ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D228217
Updated•1 year ago
|
Updated•1 year ago
|
Comment 12•1 year ago
|
||
beta Uplift Approval Request
- User impact if declined: An attacker could make Firefox use a different protocol than the one specified in the ALPN header.
- Code covered by automated testing: yes
- Fix verified in Nightly: yes
- Needs manual QE test: yes
- Steps to reproduce for manual QE testing: see comment 0
- Risk associated with taking this patch: medium
- Explanation of risk level: Our code coverage for this isn't great. I'm not 100% sure our ALPN negotiation doesn't have any bugs that would cause us to fail loading websites in specific circumstances.
- String changes made/needed: none
- Is Android affected?: yes
Comment 13•1 year ago
|
||
I misunderstood this as a certificate check bypass. Lowering to sec-moderate
Updated•1 year ago
|
Updated•1 year ago
|
Updated•1 year ago
|
Comment 14•1 year ago
|
||
| uplift | ||
Updated•1 year ago
|
I was able to reproduce the issue on Firefox 131.0.3 using Windows 11, macOS 13.6 and Ubuntu 22.04, as described in Comment 0.
Verified this with Firefox Nightly 135.0a1 (2024-12-05) and with Firefox 134.0b7 (treeherder build from Comment 14) on the previously mentioned OSes and after accessing https://foo.example.com:8443/?alt-svc=:1337, the browser traffic is redirected as follows:
- from ALPN=http/1.1 (:8443) to ALPN=h2 (:8444) and then back to ALPN=http/1.1 (:8443).
Regarding the terminal/cmd output, we noticed that when the attacker executes "[attacker] Forwarding to plain (:8445)", the process is automatically interrupted on the fixed builds:
- either the server shuts down (on macOS/Windows)
- or logs stop appearing (on Ubuntu).
I will attach a file with the script output. @valentin, could you please take a look at the output and let us know if the results are as expected? Thank you in advance!
| Assignee | ||
Comment 16•1 year ago
|
||
Thank you, Bianca. That is the expected behaviour.
Thank you for the confirmation!
Based on Comment 15 and 16 I am marking this verified as fixed on the previously mentioned versions.
Comment 18•1 year ago
|
||
Please nominate this for ESR128 approval also.
| Assignee | ||
Comment 19•1 year ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D228217
Updated•1 year ago
|
Comment 20•1 year ago
|
||
esr128 Uplift Approval Request
- User impact if declined: An attacker could make Firefox use a different protocol than the one specified in the ALPN header.
- Code covered by automated testing: yes
- Fix verified in Nightly: yes
- Needs manual QE test: yes
- Steps to reproduce for manual QE testing: see comment 0
- Risk associated with taking this patch: medium
- Explanation of risk level: Our code coverage for this isn't great. I'm not 100% sure our ALPN negotiation doesn't have any bugs that would cause us to fail loading websites in specific circumstances.
- String changes made/needed: none
- Is Android affected?: yes
Updated•1 year ago
|
Comment 21•1 year ago
|
||
| uplift | ||
Updated•1 year ago
|
| Assignee | ||
Updated•1 year ago
|
Verified as fixed on Firefox 128.6.0esr, build ID 20241213173517 (treeherder build from Comment 21), using Windows 11, macOS 13.6 and Ubuntu 22.04.
Updated•1 year ago
|
Comment 23•1 year ago
|
||
Updated•1 year ago
|
| Reporter | ||
Comment 24•1 year ago
|
||
Hey, thanks for taking care of this bug and thanks for the bounty!
I would like to publish a blog post about this bug, is there any embargo period I have to take into account or could I publish it right away?
Thanks!
Comment 25•1 year ago
|
||
This was fixed last release (~4 weeks ago). We generally wait about six weeks to make sure that even users in the more remote parts of the world had the opportunity to upgrade. If possible, I would like you to wait you for another two weeks.
| Reporter | ||
Comment 26•1 year ago
|
||
Sounds good to me! I'll publish it in two weeks then.
Updated•8 months ago
|
Description
•