Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

abnormal TS payload causes pluto daemon to restart in libreswan 4.9 #954

Closed
Zhaodl1 opened this issue Dec 20, 2022 · 15 comments
Closed

abnormal TS payload causes pluto daemon to restart in libreswan 4.9 #954

Zhaodl1 opened this issue Dec 20, 2022 · 15 comments
Labels
CVE test-present A test reproducing the problem is in or has been added to the testsuite
Milestone

Comments

@Zhaodl1
Copy link

Zhaodl1 commented Dec 20, 2022

Hi, I found a bug in libreswan-4.9 which caused the pluto daemon to restart by sending several crafted IKEv2 messages to the server.

process

first, send correct IKE_SA_INIT message and IKE_AUTH message so that the IPSEC_SA and CHILD_SA are established successfully.

then, send a REKEY_CHILD_SA message with an incorrect TSi payload. specifically, the Selector Length of the Traffic Selector need to be a different value from the real length(samller or larger, it doesn't matter). This will cause a crash when the server trys to parse this payload.

my conf

conn ikev2_test

    authby=secret
    ike=aes128-sha1;modp1536
    keyexchange=ike
    phase2=esp
    phase2alg=aes128-sha1
    compress=no
    pfs=no
    auto=add
    type=tunnel
    left=192.168.100.31
    leftnexthop=%defaultroute
    right=192.168.100.30
    rightnexthop=%defaultroute

my pluto.log for parsing the REKEY_CHILD_SA message

when parsing 1 traffic selectors , the pluto restart

Dec 20 06:04:47.516841: | *received 204 bytes from 192.168.100.30:36062 on ens33 192.168.100.31:500 using UDP
Dec 20 06:04:47.516901: | d8 ef b8 ef 3b 3a f8 a4 41 06 0f 82 7d 60 77 86
Dec 20 06:04:47.516904: | 2e 20 24 08 00 00 00 02 00 00 00 cc 29 00 00 b0
Dec 20 06:04:47.516906: | e6 8b 54 3f 30 cb cc 93 70 a6 79 47 ff c1 d3 7f
Dec 20 06:04:47.516908: | 83 6d d7 2b 44 b5 86 75 64 fb cb f0 f9 f3 e5 b7
Dec 20 06:04:47.516910: | 94 60 b4 26 3e 16 fc 6d 2d 76 9d 8e 82 11 59 c1
Dec 20 06:04:47.516911: | c3 5a 68 2c 01 5e 4f ed 8d b7 e7 56 b3 23 24 cc
Dec 20 06:04:47.516913: | dd bf e5 76 03 a3 33 36 83 5e 06 f2 71 bf 75 86
Dec 20 06:04:47.516915: | 07 f8 01 da 32 01 9e 89 9c aa a0 98 62 72 96 b8
Dec 20 06:04:47.516917: | 38 ef 32 31 1a 6f d2 50 d8 50 0f 92 49 cb 33 20
Dec 20 06:04:47.516919: | 4b 2c b0 7b f8 a4 8a ea 8f f8 ca 94 84 cf a7 ff
Dec 20 06:04:47.516921: | f1 e7 19 df c1 6b ae f9 6a c7 dc ca 3a dc ea 72
Dec 20 06:04:47.516923: | d5 08 2e 70 2f 79 15 52 a8 bf 07 ea fc 8b 3c 96
Dec 20 06:04:47.516925: | 26 0c cf 18 c3 44 f2 ea f2 09 af 5c
Dec 20 06:04:47.516933: | **parse ISAKMP Message:
Dec 20 06:04:47.516937: | initiator SPI: d8 ef b8 ef 3b 3a f8 a4
Dec 20 06:04:47.516940: | responder SPI: 41 06 0f 82 7d 60 77 86
Dec 20 06:04:47.516942: | next payload type: ISAKMP_NEXT_v2SK (0x2e)
Dec 20 06:04:47.516944: | ISAKMP version: IKEv2 version 2.0 (rfc4306/rfc5996) (0x20)
Dec 20 06:04:47.516946: | exchange type: ISAKMP_v2_CREATE_CHILD_SA (0x24)
Dec 20 06:04:47.516949: | flags: ISAKMP_FLAG_v2_IKE_INIT (0x8)
Dec 20 06:04:47.516952: | Message ID: 2 (00 00 00 02)
Dec 20 06:04:47.516955: | length: 204 (00 00 00 cc)
Dec 20 06:04:47.516957: | processing version=2.0 packet with exchange type=ISAKMP_v2_CREATE_CHILD_SA (36)
Dec 20 06:04:47.516960: | I am the IKE SA Original Responder receiving an IKEv2 CREATE_CHILD_SA request
Dec 20 06:04:47.516970: | State DB: found IKEv2 state #1 in ESTABLISHED_IKE_SA (find_v2_ike_sa)
Dec 20 06:04:47.516974: | #1 st.st_msgid_lastrecv 1 md.hdr.isa_msgid 00000002
Dec 20 06:04:47.516981: | Message ID: IKE #1 not a duplicate - message request 2 is new (SKEYSEED is known) (initiator: .sent=-1 .recv=-1 .recv_frags=0 .wip=-1 .last_sent=36587.248097 .last_recv=36587.248097 responder: .sent=1 .recv=1 .recv_frags=0 .wip=-1 .last_sent=36587.284336 .last_recv=36587.284331)
Dec 20 06:04:47.516983: | unpacking clear payload
Dec 20 06:04:47.516985: | Now let's proceed with payload (ISAKMP_NEXT_v2SK)
Dec 20 06:04:47.516988: | ***parse IKEv2 Encryption Payload:
Dec 20 06:04:47.516991: | next payload type: ISAKMP_NEXT_v2N (0x29)
Dec 20 06:04:47.516993: | flags: none (0x0)
Dec 20 06:04:47.516995: | length: 176 (00 b0)
Dec 20 06:04:47.516998: | processing payload: ISAKMP_NEXT_v2SK (len=172)
Dec 20 06:04:47.517002: | looking for transition from ESTABLISHED_IKE_SA matching CREATE_CHILD_SA request: SK (ignoring secured payloads)
Dec 20 06:04:47.517026: | trying: process rekey IKE SA request (CREATE_CHILD_SA)
Dec 20 06:04:47.517028: | matching by ignoring secured payloads
Dec 20 06:04:47.517088: | authenticator matched
Dec 20 06:04:47.517102: | stripping 4 octets as pad
Dec 20 06:04:47.517105: | #1 ikev2 ISAKMP_v2_CREATE_CHILD_SA decrypt success
Dec 20 06:04:47.517108: | Now let's proceed with payload (ISAKMP_NEXT_v2N)
Dec 20 06:04:47.517112: | **parse IKEv2 Notify Payload:
Dec 20 06:04:47.517114: | next payload type: ISAKMP_NEXT_v2SA (0x21)
Dec 20 06:04:47.517116: | flags: none (0x0)
Dec 20 06:04:47.517118: | length: 12 (00 0c)
Dec 20 06:04:47.517121: | Protocol ID: IKEv2_SEC_PROTO_ESP (0x3)
Dec 20 06:04:47.517123: | SPI size: 4 (04)
Dec 20 06:04:47.517126: | Notify Message Type: v2N_REKEY_SA (0x4009)
Dec 20 06:04:47.517128: | processing payload: ISAKMP_NEXT_v2N (len=4)
Dec 20 06:04:47.517130: | Now let's proceed with payload (ISAKMP_NEXT_v2SA)
Dec 20 06:04:47.517133: | **parse IKEv2 Security Association Payload:
Dec 20 06:04:47.517135: | next payload type: ISAKMP_NEXT_v2Ni (0x28)
Dec 20 06:04:47.517137: | flags: none (0x0)
Dec 20 06:04:47.517140: | length: 44 (00 2c)
Dec 20 06:04:47.517142: | processing payload: ISAKMP_NEXT_v2SA (len=40)
Dec 20 06:04:47.517144: | Now let's proceed with payload (ISAKMP_NEXT_v2Ni)
Dec 20 06:04:47.517146: | **parse IKEv2 Nonce Payload:
Dec 20 06:04:47.517148: | next payload type: ISAKMP_NEXT_v2TSi (0x2c)
Dec 20 06:04:47.517149: | flags: none (0x0)
Dec 20 06:04:47.517152: | length: 36 (00 24)
Dec 20 06:04:47.517154: | processing payload: ISAKMP_NEXT_v2Ni (len=32)
Dec 20 06:04:47.517156: | Now let's proceed with payload (ISAKMP_NEXT_v2TSi)
Dec 20 06:04:47.517158: | **parse IKEv2 Traffic Selector - Initiator - Payload:
Dec 20 06:04:47.517160: | next payload type: ISAKMP_NEXT_v2TSr (0x2d)
Dec 20 06:04:47.517162: | flags: none (0x0)
Dec 20 06:04:47.517164: | length: 24 (00 18)
Dec 20 06:04:47.517166: | number of TS: 1 (01)
Dec 20 06:04:47.517168: | processing payload: ISAKMP_NEXT_v2TSi (len=16)
Dec 20 06:04:47.517170: | Now let's proceed with payload (ISAKMP_NEXT_v2TSr)
Dec 20 06:04:47.517173: | **parse IKEv2 Traffic Selector - Responder - Payload:
Dec 20 06:04:47.517175: | next payload type: ISAKMP_NEXT_v2NONE (0x0)
Dec 20 06:04:47.517177: | flags: none (0x0)
Dec 20 06:04:47.517179: | length: 24 (00 18)
Dec 20 06:04:47.517181: | number of TS: 1 (01)
Dec 20 06:04:47.517183: | processing payload: ISAKMP_NEXT_v2TSr (len=16)
Dec 20 06:04:47.517187: | looking for transition from ESTABLISHED_IKE_SA matching CREATE_CHILD_SA request: SK{N(REKEY_SA),SA,Ni,TSi,TSr}
Dec 20 06:04:47.517189: | trying: process rekey IKE SA request (CREATE_CHILD_SA)
Dec 20 06:04:47.517191: | secured payloads do not match
Dec 20 06:04:47.517192: | trying: process rekey IKE SA response (CREATE_CHILD_SA)
Dec 20 06:04:47.517195: | message role does not match response
Dec 20 06:04:47.517197: | trying: process rekey Child SA request (CREATE_CHILD_SA)
Dec 20 06:04:47.517198: | secured message matched
Dec 20 06:04:47.517201: | selected state microcode process rekey Child SA request (CREATE_CHILD_SA)
Dec 20 06:04:47.517205: | #1 updating local interface from 192.168.100.31:500 to 192.168.100.31:500 using md->iface (update_ike_endpoints() +2598 /programs/pluto/state.c)
Dec 20 06:04:47.517210: | #1.st_v2_transition PARENT_R1->ESTABLISHED_IKE_SA -> ESTABLISHED_IKE_SA->ESTABLISHED_IKE_SA (v2_dispatch() +2292 /programs/pluto/ikev2.c)
Dec 20 06:04:47.517215: | Message ID: IKE #1 responder starting message request 2 (initiator: .sent=-1 .recv=-1 .recv_frags=0 .wip=-1 .last_sent=36587.248097 .last_recv=36587.248097 responder: .sent=1 .recv=1 .recv_frags=0 .wip=2 .last_sent=36587.284336 .last_recv=36587.284331)
Dec 20 06:04:47.517218: | calling processor process rekey Child SA request (CREATE_CHILD_SA)
Dec 20 06:04:47.517221: | CREATE_CHILD_SA IPsec SA rekey Protocol IKEv2_SEC_PROTO_ESP
Dec 20 06:04:47.517223: | parsing 4 raw bytes of IKEv2 Notify Payload into SPI
Dec 20 06:04:47.517229: | SPI
Dec 20 06:04:47.517232: | 0d bb 3a 00 ..:.
Dec 20 06:04:47.517234: | CREATE_CHILD_S to rekey IPsec SA(0x0dbb3a00) Protocol IKEv2_SEC_PROTO_ESP
Dec 20 06:04:47.517237: | v2 CHILD SA #2 found using their inbound (our outbound) SPI, in STATE_V2_ESTABLISHED_CHILD_SA
Dec 20 06:04:47.517239: | State DB: found IKEv2 state #2 in ESTABLISHED_CHILD_SA (find_v2_child_sa_by_outbound_spi)
Dec 20 06:04:47.517242: | #1 hasa a rekey request for "ikev2_test" #2 TSi TSr
Dec 20 06:04:47.517246: | addref fd@NULL (duplicate_state() +1538 /programs/pluto/state.c)
Dec 20 06:04:47.517252: | entry state hash_table_entries.serialno@0x55a1f6e50ea8 "ikev2_test" #3 initialized
Dec 20 06:04:47.517255: | entry state hash_table_entries.connection_serialno@0x55a1f6e50ea8 $2 initialized
Dec 20 06:04:47.517257: | entry state hash_table_entries.reqid@0x55a1f6e50ea8 "ikev2_test" #3: reqid=0 initialized
Dec 20 06:04:47.517261: | entry state hash_table_entries.ike_initiator_spi@0x55a1f6e50ea8 "ikev2_test" #3: 00 00 00 00 00 00 00 00 initialized
Dec 20 06:04:47.517264: | entry state hash_table_entries.ike_spis@0x55a1f6e50ea8 "ikev2_test" #3: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 initialized
Dec 20 06:04:47.517266: | creating state object #3 at 0x55a1f6e50ea8
Dec 20 06:04:47.517283: | entry state hash_table_entries.serialno@0x55a1f6e50ea8 "ikev2_test" #3 added to hash table bucket 0x55a1f5778b20
Dec 20 06:04:47.517286: | entry state hash_table_entries.connection_serialno@0x55a1f6e50ea8 $2 added to hash table bucket 0x55a1f5774ea0
Dec 20 06:04:47.517289: | entry state hash_table_entries.reqid@0x55a1f6e50ea8 "ikev2_test" #3: reqid=0 added to hash table bucket 0x55a1f576e0a0
Dec 20 06:04:47.517292: | entry state hash_table_entries.ike_initiator_spi@0x55a1f6e50ea8 "ikev2_test" #3: d8 ef b8 ef 3b 3a f8 a4 added to hash table bucket 0x55a1f576dbc0
Dec 20 06:04:47.517295: | entry state hash_table_entries.ike_spis@0x55a1f6e50ea8 "ikev2_test" #3: d8 ef b8 ef 3b 3a f8 a4 41 06 0f 82 7d 60 77 86 added to hash table bucket 0x55a1f57671c0
Dec 20 06:04:47.517298: | pstats #3 ikev2.child started
Dec 20 06:04:47.517301: | duplicating state object #1 "ikev2_test" as #3 for IPSEC SA
Dec 20 06:04:47.517304: | #3 setting local endpoint to 192.168.100.31:500 from #1.st_localport (duplicate_state() +1553 /programs/pluto/state.c)
Dec 20 06:04:47.517310: | child state #3: UNDEFINED(ignore) => REKEY_CHILD_R0(established IKE SA)
Dec 20 06:04:47.517313: | #3.st_v2_transition NULL -> REKEY_CHILD_R0->ESTABLISHED_CHILD_SA (new_v2_child_state() +1636 /programs/pluto/state.c)
Dec 20 06:04:47.517317: | constructing ESP/AH proposals with default DH NONE for ikev2_test (Child SA proposals (initiating rekey))
Dec 20 06:04:47.517322: | converting proposal AES_CBC_128-HMAC_SHA1_96 to ikev2 ...
Dec 20 06:04:47.517328: | ... ikev2_proposal: 1:ESP=AES_CBC_128-HMAC_SHA1_96-NONE-ENABLED+DISABLED
Dec 20 06:04:47.517331: | TSi: parsing 1 traffic selectors
Dec 20 06:04:48.074282: | releasing whack fd@(nil) for (main() +1602 /programs/pluto/plutomain.c)
Dec 20 06:04:48.074334: | delref fd@NULL (main() +1602 /programs/pluto/plutomain.c)
Dec 20 06:04:48.074348: | delref fd@NULL (main() +1602 /programs/pluto/plutomain.c)
Dec 20 06:04:48.074360: | checking IKEv1 state table

related code in ikev2_ts.c

I think this is the code that causes the error. When parsing an incorrect TSi payload with wrong selecter length, pbs_in_struct return early, so the ts_body_pbs is not initialized.

        struct ikev2_ts_header ts_h;
	struct pbs_in ts_body_pbs;

	d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
		  &ts_h, sizeof(ts_h), &ts_body_pbs);

	switch (ts_h.isath_type) {
	case IKEv2_TS_IPV4_ADDR_RANGE:
	case IKEv2_TS_IPV6_ADDR_RANGE:
	{
		ts->ipprotoid = ts_h.isath_ipprotoid;

		/* read and fill in port range */
		struct ikev2_ts_portrange pr;

		d = pbs_in_struct(&ts_body_pbs, &ikev2_ts_portrange_desc,
			  &pr, sizeof(pr), NULL);

I also tested several other versions, it seems to have the same problem in libreswan 4.5 - 4.8

@cagney
Copy link
Collaborator

cagney commented Dec 20, 2022

Can you try mainline which has:

		struct ikev2_ts_header ts_h;
		struct pbs_in ts_body_pbs;
		d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
				  &ts_h, sizeof(ts_h), &ts_body_pbs);
		if (d != NULL) {
			llog_diag(RC_LOG, logger, &d, "%s", "");
			return false;
		}

See 2aecf49 and 7ceef9a

@Zhaodl1
Copy link
Author

Zhaodl1 commented Dec 21, 2022

I tried this and it looks like the problem has been fixed. Thank you very much !

Can you try mainline which has:

		struct ikev2_ts_header ts_h;
		struct pbs_in ts_body_pbs;
		d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
				  &ts_h, sizeof(ts_h), &ts_body_pbs);
		if (d != NULL) {
			llog_diag(RC_LOG, logger, &d, "%s", "");
			return false;
		}

See 2aecf49 and 7ceef9a

@cagney cagney added the test-needed The issue lacks a test case label Dec 21, 2022
@dkg
Copy link
Contributor

dkg commented Feb 22, 2023

This is apparently now known as CVE-2023-23009.

2aecf49 and 7ceef9a seem awfully verbose to fix this problem. is there a more narrowly-targeted fix that can be applied to 4.9?

are versions before 4.9 vulnerable as well? the reporter suggests that versions 4.5 through 4.8 have also been tested and found vulnerable. It would be great to have a targeted fix that could be applied to older versions.

@dkg
Copy link
Contributor

dkg commented Feb 22, 2023

For example, is this a sufficient fix?

diff --git a/programs/pluto/ikev2_ts.c b/programs/pluto/ikev2_ts.c
index 3f7519ca38..f06c40ba46 100644
--- a/programs/pluto/ikev2_ts.c
+++ b/programs/pluto/ikev2_ts.c
@@ -437,6 +437,11 @@ static bool v2_parse_tss(struct payload_digest *const ts_pd,
                d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
                          &ts_h, sizeof(ts_h), &ts_body_pbs);
 
+               if (d != NULL) {
+                       llog_diag(RC_LOG, logger, &d, "%s", "");
+                       return false;
+               }
+
                switch (ts_h.isath_type) {
                case IKEv2_TS_IPV4_ADDR_RANGE:
                case IKEv2_TS_IPV6_ADDR_RANGE:

@cagney
Copy link
Collaborator

cagney commented Feb 22, 2023

yes; my recollection is that the peer has to be authenticated for this code path to be reached

@letoams
Copy link
Member

letoams commented Feb 23, 2023 via email

@dkg
Copy link
Contributor

dkg commented Feb 24, 2023

We're discussing this over at https://bugs.debian.org/1031821

@cagney
Copy link
Collaborator

cagney commented Feb 24, 2023

to answer some questions:
"See 2aecf49 and 7ceef9a" bracket the bug so v4.2 on

In 4.9, for instance, the call to verify_v2AUTH_and_log() is made before the TS payloads start to be processed.

lsw-vault pushed a commit that referenced this issue Mar 1, 2023
@cagney cagney closed this as completed Mar 1, 2023
@cagney cagney added test-present A test reproducing the problem is in or has been added to the testsuite and removed test-needed The issue lacks a test case labels Mar 1, 2023
@carnil
Copy link

carnil commented Mar 2, 2023

@cagney, @dkg

For example, is this a sufficient fix?

diff --git a/programs/pluto/ikev2_ts.c b/programs/pluto/ikev2_ts.c
index 3f7519ca38..f06c40ba46 100644
--- a/programs/pluto/ikev2_ts.c
+++ b/programs/pluto/ikev2_ts.c
@@ -437,6 +437,11 @@ static bool v2_parse_tss(struct payload_digest *const ts_pd,
                d = pbs_in_struct(&ts_pd->pbs, &ikev2_ts_header_desc,
                          &ts_h, sizeof(ts_h), &ts_body_pbs);
 
+               if (d != NULL) {
+                       llog_diag(RC_LOG, logger, &d, "%s", "");
+                       return false;
+               }
+
                switch (ts_h.isath_type) {
                case IKEv2_TS_IPV4_ADDR_RANGE:
                case IKEv2_TS_IPV6_ADDR_RANGE:

For versions earlier than d7d415b in v4.4 I guess the patch needs to be different and using log_diag() instead.

Worth mentioning as well in https://libreswan.org/security/CVE-2023-23009/CVE-2023-23009.txt ?

@letoams
Copy link
Member

letoams commented Mar 2, 2023 via email

@paulwouters
Copy link
Member

updated announcement and patches are now published. thanks

@dkg
Copy link
Contributor

dkg commented Mar 3, 2023

I'm looking at the patches published at https://libreswan.org/security/CVE-2023-23009/ and i think they are correct, but the diffs themselves are malformed (not machine-interpretable). In particular, the --- lines appear to have been subject to OpenPGP's Cleartext Signature Framework's escaping mechanism multiple times, or something like that. (even the non-signed versions of the patches seem to be malformed in this way)

I've also noted that the OpenPGP signatures in them have divergent validation interpretations in different OpenPGP implementations. I'm not sure whether this has to do with confusions around escaping, or trailing newlines, or something else.

I don't think there's anything specific that you need to do here at the moment -- you've published sufficient information for anyone downstream to fix the issue -- but just wanted to give you a heads-up that there's probably something in your toolchain that isn't working as intended.

@letoams
Copy link
Member

letoams commented Mar 3, 2023 via email

@dkg
Copy link
Contributor

dkg commented Mar 3, 2023

thanks, @letoams !

@bleve
Copy link
Collaborator

bleve commented Mar 3, 2023

I just pushed missing commit so tag should show now.

cagney added a commit to cagney/libreswan that referenced this issue Mar 14, 2023
@cagney cagney added this to the v4.10 milestone Apr 6, 2023
@cagney cagney added the CVE label May 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CVE test-present A test reproducing the problem is in or has been added to the testsuite
Projects
None yet
Development

No branches or pull requests

7 participants