Re: [Masque] Forwarded Mode infinite loops

Tommy Pauly <tpauly@apple.com> Tue, 24 October 2023 03:01 UTC

Return-Path: <tpauly@apple.com>
X-Original-To: masque@ietfa.amsl.com
Delivered-To: masque@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id BE3B6C17C507 for <masque@ietfa.amsl.com>; Mon, 23 Oct 2023 20:01:40 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.104
X-Spam-Level:
X-Spam-Status: No, score=-2.104 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_FONT_LOW_CONTRAST=0.001, HTML_MESSAGE=0.001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_BLOCKED=0.001, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=apple.com
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id dL6ToMOARN9M for <masque@ietfa.amsl.com>; Mon, 23 Oct 2023 20:01:36 -0700 (PDT)
Received: from ma-mailsvcp-mx-lapp01.apple.com (ma-mailsvcp-mx-lapp01.apple.com [17.32.222.22]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 0FD65C1519A4 for <masque@ietf.org>; Mon, 23 Oct 2023 20:01:35 -0700 (PDT)
Received: from rn-mailsvcp-mta-lapp04.rno.apple.com (rn-mailsvcp-mta-lapp04.rno.apple.com [10.225.203.152]) by ma-mailsvcp-mx-lapp01.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPS id <0S3000W43J2IUB40@ma-mailsvcp-mx-lapp01.apple.com> for masque@ietf.org; Mon, 23 Oct 2023 20:01:35 -0700 (PDT)
X-Proofpoint-ORIG-GUID: FrnN850BQs6TTsFrI_UkwDQasveLvdGl
X-Proofpoint-GUID: FrnN850BQs6TTsFrI_UkwDQasveLvdGl
X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.619, 18.0.980 definitions=2023-10-24_01:2023-10-19, 2023-10-23 signatures=0
X-Proofpoint-Spam-Details: rule=interactive_user_notspam policy=interactive_user score=0 suspectscore=0 phishscore=0 malwarescore=0 spamscore=0 bulkscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2310170001 definitions=main-2310240025
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=apple.com; h=from : message-id : content-type : mime-version : subject : date : in-reply-to : cc : to : references; s=20180706; bh=GLRdXhqJnHfpd5yUre1S+xEnLA+wFIx3KPV0M/YsRp8=; b=sOavuo7UYXUcwIuUajWx/s6TSAz7A4OjS6LIg9dRL+n1bTWhZC/yXmQuCjekBeMHcU8j pAszz9fTc+VSgkqBa8dHfW+XVtiHd46wSEcHYY/t/H2E0wVf+6B3CA4HzQGuolEDixZz xpCLAJtCwDnGZr5nznd+uRbuzLAYiA5HR13DR5vsv7IJxHYrHR8SpKHkeTIH/3wjJUAC rFCFFTuXGBE2HyJjj39Nv+D9oRbtkBQQIclRHf54fkTiXHjJ0GNhf7hivezPXKijCv8p 94t1xJfzt3+YDVw/ve90TnmK53KEwtmoaECIDiVdiInjt2RNkSLKhRBmx/MLg156mIv+ Yw==
Received: from rn-mailsvcp-mmp-lapp01.rno.apple.com (rn-mailsvcp-mmp-lapp01.rno.apple.com [17.179.253.14]) by rn-mailsvcp-mta-lapp04.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPS id <0S3000HWGJ2JYD10@rn-mailsvcp-mta-lapp04.rno.apple.com>; Mon, 23 Oct 2023 20:01:31 -0700 (PDT)
Received: from process_milters-daemon.rn-mailsvcp-mmp-lapp01.rno.apple.com by rn-mailsvcp-mmp-lapp01.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) id <0S3000A00J245R00@rn-mailsvcp-mmp-lapp01.rno.apple.com>; Mon, 23 Oct 2023 20:01:31 -0700 (PDT)
X-Va-A:
X-Va-T-CD: 8d45deca0a60b8e84b634a23cb93b003
X-Va-E-CD: 3e0da6a25dd7f257c76b58afa2095f44
X-Va-R-CD: 34cb064055ddabdb3a11583980f6e222
X-Va-ID: 6201cc8e-5fd9-4d7c-94e7-68b1043b908f
X-Va-CD: 0
X-V-A:
X-V-T-CD: 8d45deca0a60b8e84b634a23cb93b003
X-V-E-CD: 3e0da6a25dd7f257c76b58afa2095f44
X-V-R-CD: 34cb064055ddabdb3a11583980f6e222
X-V-ID: 708123af-8aa8-43c4-bcf1-f8ec9d6e8402
X-V-CD: 0
X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.619, 18.0.980 definitions=2023-10-24_01:2023-10-19, 2023-10-23 signatures=0
Received: from smtpclient.apple ([17.11.153.17]) by rn-mailsvcp-mmp-lapp01.rno.apple.com (Oracle Communications Messaging Server 8.1.0.23.20230328 64bit (built Mar 28 2023)) with ESMTPSA id <0S3000SADJ2H0R00@rn-mailsvcp-mmp-lapp01.rno.apple.com>; Mon, 23 Oct 2023 20:01:29 -0700 (PDT)
From: Tommy Pauly <tpauly@apple.com>
Message-id: <34F58C3B-7677-4974-8AB9-CDF011EABA1B@apple.com>
Content-type: multipart/alternative; boundary="Apple-Mail=_FA37E9F5-AAE7-4B4C-9624-E049D61BD791"
MIME-version: 1.0 (Mac OS X Mail 16.0 \(3774.100.2.1.4\))
Date: Mon, 23 Oct 2023 20:01:19 -0700
In-reply-to: <CAM4esxShEYAgZ-LhVSPtdaajiAhRx99tj0ef-t+AmJGBiHMOOA@mail.gmail.com>
Cc: David Schinazi <dschinazi.ietf@gmail.com>, MASQUE <masque@ietf.org>
To: Martin Duke <martin.h.duke@gmail.com>
References: <CAM4esxRzTu=njLp7Uk=4AvObxD5j0FG1fQHKtoyDGFWF7q1jdg@mail.gmail.com> <BN8PR15MB3281FF073C549E3A39DD087BB3DBA@BN8PR15MB3281.namprd15.prod.outlook.com> <CAM4esxRKTNdGBpiO5_s33UikPnSG54K1dNKYua6_ca3f4jE2=A@mail.gmail.com> <BN8PR15MB32817A645AB33154DE9ACFFEB3DBA@BN8PR15MB3281.namprd15.prod.outlook.com> <CAM4esxSMEtExuW0WewKCjz3Xc+_pe7czdx_gRcqe7uqZJ8B8Rw@mail.gmail.com> <CAM4esxQf6T7G8TWLcKsF0=cEyvndN2HHK+D4s8EvOF+Z=gXbMQ@mail.gmail.com> <CAM4esxTwkE1wHwFuLDLx8h5qzRtWTFhfQgWgteWPSoTeEuQQuA@mail.gmail.com> <CAPDSy+7cPETw-CEd910AodgV3ADJuFsfDRi3FAxyY=pYVRoc-Q@mail.gmail.com> <CAM4esxShEYAgZ-LhVSPtdaajiAhRx99tj0ef-t+AmJGBiHMOOA@mail.gmail.com>
X-Mailer: Apple Mail (2.3774.100.2.1.4)
Archived-At: <https://mailarchive.ietf.org/arch/msg/masque/C3d5A2dZPpY0vbf0Tt-1gEANSCU>
Subject: Re: [Masque] Forwarded Mode infinite loops
X-BeenThere: masque@ietf.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: Multiplexed Application Substrate over QUIC Encryption <masque.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/masque>, <mailto:masque-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/masque/>
List-Post: <mailto:masque@ietf.org>
List-Help: <mailto:masque-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/masque>, <mailto:masque-request@ietf.org?subject=subscribe>
X-List-Received-Date: Tue, 24 Oct 2023 03:01:40 -0000

It was useful for me to draw this out in (unnecessary) detail to show how this only needs the ingress IP to be shared, not the egress IP.

To help go through this, let me fill in the example you gave with more details about IPs and ports — since the forwarding mappings depend on these “sockets”.

Let’s start with a case where the addresses aren’t being shared.

C has address 1111::1
P1 has ingress address 2222::2, and egress address 3333::3
P2 has ingress address 4444::4, and egress address 5555::5
P3 has ingress address 6666::6, and egress address 7777::7
T has ingress address 8888::8

C is set up to receive CID4 on 1111::1 port 10000 from 2222::2 port 443
P1 is set up to receive CID3 on 3333::3 port 20000 from 4444::4 port 443, and forward it as CID4 to 1111::1 port 10000 from 2222::2 port 443
P2 is set up to receive CID2 on 5555::5 port 30000 from 2222::2 port 443, and forward it as CID3 to 3333::3 port 20000 from 4444::4 port 443
P1 is set up to receive CID1 on 3333::3 port 40000 from 6666::6 port 443, and forward it as CID2 to 5555::5 port 30000 from 2222::2 port 443
P3 is set up to receive CID0 on 7777::7 port 50000 from 8888::8 port 443, and forward it as CID1 to 3333::3 port 40000 from 6666::6 port 443
T sends using CID0 to 7777::7 port 50000 from 8888::8 port 443

In this case, since there is no address sharing, if the client tells P2 to instead map from (CID2 on 5555::5 port 30000 from 2222::2 port 443) to (CID1 to 3333::3 port 20000 from 4444::4 port 443), the connection will break, but there will be no loop, since P1 won’t allow receiving CID1 on that socket.


Then, let’s explore the case of shared addresses. If we only have P2 and P3 share an ingress VIP, and P1 reuses sockets on egress, we have the following:

C has address 1111::1
P1 has ingress address 2222::2, and egress address 3333::3
P2 has ingress address 4444::4, and egress address 5555::5
P3 has ingress address 4444::4, and egress address 7777::7
T has ingress address 8888::8

C is set up to receive CID4 on 1111::1 port 10000 from 2222::2 port 443
P1 is set up to receive CID3 on 3333::3 port 20000 from 4444::4 port 443, and forward it as CID4 to 1111::1 port 10000 from 2222::2 port 443
P2 is set up to receive CID2 on 5555::5 port 30000 from 2222::2 port 443, and forward it as CID3 to 3333::3 port 20000 from 4444::4 port 443
P1 is set up to receive CID1 on 3333::3 port 20000 from 4444::4 port 443, and forward it as CID2 to 5555::5 port 30000 from 2222::2 port 443
P3 is set up to receive CID0 on 7777::7 port 50000 from 8888::8 port 443, and forward it as CID1 to 3333::3 port 20000 from 4444::4 port 443
T sends using CID0 to 7777::7 port 50000 from 8888::8 port 443

Then, if the client tells P2 to instead map from (CID2 on 5555::5 port 30000 from 2222::2 port 443) to (CID1 to 3333::3 port 20000 from 4444::4 port 443), the loop occurs because there are two mappings for receiving on P1 that differ only in CID.

Tommy

> On Oct 23, 2023, at 7:08 PM, Martin Duke <martin.h.duke@gmail.com> wrote:
> 
> The reason I put in the point about VIPs is that P1 cannot distinguish between a packet from P2 and P3 if they share an ingress VIP 
> 
> If they're from different IP addresses it's sufficient for P1 to check the source IP of packets arriving from the target 
> 
> Does that answer your question?
> 
> 
> On Mon, Oct 23, 2023, 18:34 David Schinazi <dschinazi.ietf@gmail.com <mailto:dschinazi.ietf@gmail.com>> wrote:
>> Hi Martin,
>> 
>> I don't understand how the fact that P2 and P3 share a VIP impacts the
>> attack. Thinking about this some more, maybe the issue is that we mean
>> different things when we say VIP? In my mind:
>> 
>> * a "VIP" is an (IP address, UDP port) tuple. The V stands for virtual in the
>>   sense that two separate servers can both have the same IP due to anycast.
>> 
>> * an "ingress VIP" is the VIP that the client sends packets to. In the document
>>   this is called a "client-facing socket".
>> 
>> * an "egress VIP" is the VIP that the target sends packets to. In the document
>>   this is called a "target-facing socket".
>> 
>> Ingress VIPs are very common in practice. Many CDNs will use anycast and
>> have an ingress VIP that represents a fleet of frontends. Egress VIPs however,
>> don't make any sense to me, because you'd never want anycast on egress IPs.
>> 
>> Could you help reframe the P2/P3 shared VIP point in terms of ingress and
>> egress VIPs please?
>> 
>> Thanks,
>> David
>> 
>> 
>> On Fri, Oct 20, 2023 at 3:00 PM Martin Duke <martin.h.duke@gmail.com <mailto:martin.h.duke@gmail.com>> wrote:
>>> As I continue to think about this, I'm not sure that authentication even solves the problem. The client could authenticate with each client, sure, but to P1, P2 and P3 are essentially targets. Targets, obviously will not do anything special just because this is a connection over MASQUE, so there cannot be a special mechanism for P1 to verify authenticity of packets from the target, unless it has the target-client session keys.
>>> 
>>> On Fri, Oct 20, 2023 at 12:14 PM Martin Duke <martin.h.duke@gmail.com <mailto:martin.h.duke@gmail.com>> wrote:
>>>> I should add that another way to thwart this attack is to require the proxy to open a new target-facing socket for every client request. Then the packet incoming to P1 would be disambiguated by the destination IP/port. Not opening a new socket is currently allowed in the spec, which IIUC is a change from CONNECT-UDP.
>>>> 
>>>> So the proxy vulnerability occurs if 
>>>> (1) P2/P3 share a VIP,
>>>> (2) P1 is not load balanced, so that the attacker can directly target it, and
>>>> (3) P1 is not opening unique target-facing sockets for each request, even though the target IP/port are the same.
>>>> 
>>>> On Fri, Oct 20, 2023 at 11:56 AM Martin Duke <martin.h.duke@gmail.com <mailto:martin.h.duke@gmail.com>> wrote:
>>>>> Forwarded packets from the client SHOULD count. The draft is silent about forwarded packets from the target.
>>>>> 
>>>>> But fair enough, the client needs to do just enough to keep it alive.
>>>>> 
>>>>> On Fri, Oct 20, 2023 at 11:15 AM Ben Schwartz <bemasc@meta.com <mailto:bemasc@meta.com>> wrote:
>>>>>> I'm not sure the client can actually "go away".  If the HTTP connection ends, the forwarding sessions will also end, so this can be addressed by setting a QUIC max_idle_timeout.
>>>>>> 
>>>>>> This assumes that forwarded packets don't count toward the idle timeout, which they shouldn't.  We might need to say that in the draft.
>>>>>> 
>>>>>> --Ben
>>>>>> From: Masque <masque-bounces@ietf.org <mailto:masque-bounces@ietf.org>> on behalf of Martin Duke <martin.h.duke@gmail.com <mailto:martin.h.duke@gmail.com>>
>>>>>> Sent: Friday, October 20, 2023 1:47 PM
>>>>>> To: Ben Schwartz <bemasc@meta.com <mailto:bemasc@meta.com>>
>>>>>> Cc: MASQUE <masque@ietf.org <mailto:masque@ietf.org>>
>>>>>> Subject: Re: [Masque] Forwarded Mode infinite loops
>>>>>>  
>>>>>> Ben,
>>>>>> 
>>>>>> Replies inline.
>>>>>> 
>>>>>> On Fri, Oct 20, 2023 at 9:53 AM Ben Schwartz <bemasc@meta.com <mailto:bemasc@meta.com>> wrote:
>>>>>> Loops!  This is a fun attack.  It seems like there are probably lots of loopy configurations if you have access to two or more proxies.
>>>>>> 
>>>>>> Most of the encryption discussion for forwarded mode has focused on unauthenticated encryption, which wouldn't help here.
>>>>>> 
>>>>>> I have not seen a written proposal in this space, but if the encryption scheme has no authentication properties it doesn't mitigate pretty basic DoS attacks. Perhaps this attack creates a new design requirement for encryption?
>>>>>>  
>>>>>> Changing who chooses the Connection IDs could help, but proxy-chosen CIDs are not necessarily high entropy, so there's no clear guarantee.
>>>>>> 
>>>>>> IIUC your contention is that this arises when P3 and P2 both happen to select CID1 as the virtual connection ID. A well-intentioned client would therefore register CID1 to P1 twice, and P1 would reject it as a duplicate in one of those instances, avoiding a loop.
>>>>>> 
>>>>>> However, a malicious client could note the conflict and just register CID3 to P1 instead, creating the same attack.
>>>>>> 
>>>>>> I do think that if we try to fix this with proxy-chooses, there need to be some minimum size limits to avoid this kind of thing. If CIDs are 64 bits (or even 32!) I feel pretty good about this not being an exploitable attack.
>>>>>>  
>>>>>> Ultimately, I'm not sure this matters.  A hostile client can impose pretty much arbitrarily amplified load on the forwarder anyway, e.g. by downloading a large file and forging ACKs to dropped packets so that congestion control ramps up to infinity.  Forwarders will need defenses to rate-limit or cap abusive clients.  That said, it's probably worth fixing if there's an easy solution.
>>>>>> 
>>>>>> I agree there are other attacks -- in fact, I have other amplification attacks in mind, which will write about another day.
>>>>>> 
>>>>>> What is particularly pernicious about this attack is that a single attacker packet results in infinity packets in the proxy path. This flow can be "rate limited" but the client can go away and this persists forever.
>>>>>> 
>>>>>> Buit 
>>>>>>  
>>>>>> 
>>>>>> --Ben
>>>>>> From: Masque <masque-bounces@ietf.org <mailto:masque-bounces@ietf.org>> on behalf of Martin Duke <martin.h.duke@gmail.com <mailto:martin.h.duke@gmail.com>>
>>>>>> Sent: Wednesday, October 18, 2023 5:25 PM
>>>>>> To: MASQUE <masque@ietf.org <mailto:masque@ietf.org>>
>>>>>> Subject: [Masque] Forwarded Mode infinite loops
>>>>>>  
>>>>>> Hello MASQUE,
>>>>>> 
>>>>>> (with no hats on)
>>>>>> 
>>>>>> I was playing with some annoying but manageable amplification attacks on CONNECT-UDP forwarding mode. Those will have to wait for another day, because the current draft has a fatal vulnerability, though one that we can fix pretty easily.
>>>>>> 
>>>>>> If I've gotten something incorrect, please say so! It wouldn't be the first time.
>>>>>> 
>>>>>> Recall that for forwarded mode, clients notify the proxy of the connection ID they are advertising to the target, and in the same capsule propose a "virtual connection ID" for use on the proxy-client path. (IIUC, this virtual CID is to prevent association of the packets on either end of the proxy).
>>>>>> 
>>>>>> I reiterate that we are talking about the CLIENT connection ID and its virtual counterparts, not the target.
>>>>>> 
>>>>>> Consider the following very stupid topology that a client C could construct to target T via various proxies. Crucially, P2 and P3 are from the same provider and share a VIP.* This wrinkle eliminates some really simple mitigations for what I'm about to describe.
>>>>>> 
>>>>>> C -> P1 -> P2 -> P1 -> P3 ->  T
>>>>>> 
>>>>>> An otherwise well-intentioned client would advertise client Connection ID CID0 to T, and via REGISTER_CLIENT_CID capsules might set up the rest like so:
>>>>>> 
>>>>>> Nodes        C     P1     P2    P1    P3     T
>>>>>> CID on wire    CID4   CID3  CID2  CID1   CID0
>>>>>> 
>>>>>> So far, so good. A packet that leaves T will be destined for CID0. The destination CID will be rewritten in turn, arriving at C with CID4.
>>>>>> 
>>>>>> However, a malicious client can register CIDs with the proxies as follows:
>>>>>> Nodes        C     P1            P2      P1      P3     T
>>>>>> CID on wire    CID4   CID3 / CID1    CID2    CID1   CID0
>>>>>> 
>>>>>> The only change is that P2 is "incorrectly" configured by the client to rewrite incoming CID2 as CID1. As far as P2 is concerned, everything is seems legit unless it is sharing enormous amounts of CID state with its partner P3. Everything else is unchanged.
>>>>>> 
>>>>>> Thus, a packet leaving T with CID0 will be rewritten to CID1 and routed to P1;  P1 will then route it to P2 with CID2. Then that gets routed back to P1 with CID1, and the P1-P2-P1 loop continues to infinity. The attacker can put as many proxy hops as it likes in that chain.
>>>>>> 
>>>>>> There are a few pretty simple things that can break this doom loop.
>>>>>> - Do encryption at each MASQUE hop, as previously proposed. This verifies the previous hop of the packet and drops those where the CID does not have the correct origin.
>>>>>> - Have the proxy provide the virtual CID instead of the client. Client control is the root of these problems.
>>>>>> - Eliminate virtual client CIDs and just take the L on linkability in that case
>>>>>> 
>>>>>> Martin
>>>>>> 
>>>>>> * Interestingly, this attack requires at least one proxy in the path (P1 in this case) to not be load balanced or have an easily manipulated load balancer, so that two QUIC connection attempts can with high probability go to the same device.
>>> -- 
>>> Masque mailing list
>>> Masque@ietf.org <mailto:Masque@ietf.org>
>>> https://www.ietf.org/mailman/listinfo/masque
> -- 
> Masque mailing list
> Masque@ietf.org
> https://www.ietf.org/mailman/listinfo/masque