]>
Commit | Line | Data |
---|---|---|
05c80ef3 AM |
1 | Date: Sun, 1 Oct 2023 11:33:26 +0200\r |
2 | To: exim-dev@lists.exim.org\r | |
3 | From: Florian Zumbiehl via Exim-dev <exim-dev@lists.exim.org>\r | |
4 | \r | |
5 | Hi,\r | |
6 | \r | |
7 | below you find a patch that fixes some (probably three?) of what I guess are\r | |
8 | the vulnerabilities reported by ZDI.\r | |
9 | \r | |
10 | Please note that the patch is only mildly tested, it is developed based on\r | |
11 | the git master branch, but can be applied to older versions with minor\r | |
12 | massaging. If you go back far enough, proxy.c was part of smtp_in.c, but if\r | |
13 | you adjust for that, the patch can be made to apply there, too.\r | |
14 | \r | |
15 | Obviously, I have no idea whether this actually addresses what ZDI has\r | |
16 | reported, but if not, these probably should be fixed, too, and if so, given\r | |
17 | the fact that I managed to rather easily find these vulnerabilities based\r | |
18 | on the information that's publicly available, I don't think there is much\r | |
19 | point to trying to keep this secret any longer--if anything, it's\r | |
20 | counterproductive.\r | |
21 | \r | |
22 | Also mind you that this is a hot fix, it's neither elegant, nor does it do\r | |
23 | any useful error reporting, the goal was simply to prevent out of bounds\r | |
24 | accesses.\r | |
25 | \r | |
26 | Florian\r | |
27 | \r | |
28 | ---\r | |
29 | \r | |
30 | diff --git a/src/src/auths/external.c b/src/src/auths/external.c\r | |
31 | index 078aad0..54966e6 100644\r | |
32 | --- a/src/src/auths/external.c\r | |
33 | +++ b/src/src/auths/external.c\r | |
34 | @@ -101,6 +101,9 @@ if (expand_nmax == 0) /* skip if rxd data */\r | |
35 | if ((rc = auth_prompt(CUS"")) != OK)\r | |
36 | return rc;\r | |
37 | \r | |
38 | +if (expand_nmax != 1)\r | |
39 | + return FAIL;\r | |
40 | +\r | |
41 | if (ob->server_param2)\r | |
42 | {\r | |
43 | uschar * s = expand_string(ob->server_param2);\r | |
44 | diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c\r | |
45 | index 222ccea..66967d6 100644\r | |
46 | --- a/src/src/auths/spa.c\r | |
47 | +++ b/src/src/auths/spa.c\r | |
48 | @@ -166,12 +166,18 @@ if (auth_get_no64_data(&data, msgbuf) != OK)\r | |
49 | return FAIL;\r | |
50 | \r | |
51 | /* dump client response */\r | |
52 | -if (spa_base64_to_bits(CS &response, sizeof(response), CCS data) < 0)\r | |
53 | +int l = spa_base64_to_bits(CS &response, sizeof(response), CCS data);\r | |
54 | +if (l < 0)\r | |
55 | {\r | |
56 | DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in "\r | |
57 | "response: %s\n", data);\r | |
58 | return FAIL;\r | |
59 | }\r | |
60 | +if(l < (char *)&response.buffer - (char *)&response)return FAIL;\r | |
61 | +unsigned long o = IVAL(&response.uUser.offset, 0);\r | |
62 | +if((l < o) || (l - o < SVAL(&response.uUser.len, 0)))return FAIL;\r | |
63 | +o = IVAL(&response.ntResponse.offset, 0);\r | |
64 | +if((l < o) || (l - o < 24))return FAIL;\r | |
65 | \r | |
66 | /***************************************************************\r | |
67 | PH 07-Aug-2003: The original code here was this:\r | |
68 | @@ -346,7 +352,10 @@ if (!smtp_read_response(sx, US buffer, buffsize, '3', timeout))\r | |
69 | \r | |
70 | /* convert the challenge into the challenge struct */\r | |
71 | DSPA("\n\n%s authenticator: challenge (%s)\n\n", ablock->name, buffer + 4);\r | |
72 | -spa_base64_to_bits(CS (&challenge), sizeof(challenge), CCS (buffer + 4));\r | |
73 | +int l = spa_base64_to_bits(CS (&challenge), sizeof(challenge), CCS (buffer + 4));\r | |
74 | +if((l < 0) || (l < (char *)&challenge.buffer - (char *)&challenge))return FAIL;\r | |
75 | +unsigned long o = IVAL(&challenge.uDomain.offset, 0);\r | |
76 | +if((l < o) || (l - o < SVAL(&challenge.uDomain.len, 0)))return FAIL;\r | |
77 | \r | |
78 | spa_build_auth_response(&challenge, &response, CS username, CS password);\r | |
79 | spa_bits_to_base64(US msgbuf, US &response, spa_request_length(&response));\r | |
80 | diff --git a/src/src/proxy.c b/src/src/proxy.c\r | |
81 | index fbce111..8dd7034 100644\r | |
82 | --- a/src/src/proxy.c\r | |
83 | +++ b/src/src/proxy.c\r | |
84 | @@ -93,6 +93,8 @@ while (capacity > 0)\r | |
85 | do { ret = read(fd, to, 1); } while (ret == -1 && errno == EINTR && !had_command_timeout);\r | |
86 | if (ret == -1)\r | |
87 | return -1;\r | |
88 | + if (!ret)\r | |
89 | + break;\r | |
90 | have++;\r | |
91 | if (last)\r | |
92 | return have;\r | |
93 | @@ -254,6 +256,8 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0))\r | |
94 | goto proxyfail;\r | |
95 | }\r | |
96 | \r | |
97 | + if (ret < 16)\r | |
98 | + goto proxyfail;\r | |
99 | /* The v2 header will always be 16 bytes per the spec. */\r | |
100 | size = 16 + ntohs(hdr.v2.len);\r | |
101 | DEBUG(D_receive) debug_printf("Detected PROXYv2 header, size %d (limit %d)\n",\r | |
102 | @@ -274,7 +278,7 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0))\r | |
103 | {\r | |
104 | retmore = read(fd, (uschar*)&hdr + ret, size-ret);\r | |
105 | } while (retmore == -1 && errno == EINTR && !had_command_timeout);\r | |
106 | - if (retmore == -1)\r | |
107 | + if (retmore < 1)\r | |
108 | goto proxyfail;\r | |
109 | DEBUG(D_receive) proxy_debug(US &hdr, ret, ret + retmore);\r | |
110 | ret += retmore;\r | |
111 | @@ -297,6 +301,8 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0)\r | |
112 | switch (hdr.v2.fam)\r | |
113 | {\r | |
114 | case 0x11: /* TCPv4 address type */\r | |
115 | + if (ret < 28)\r | |
116 | + goto proxyfail;\r | |
117 | iptype = US"IPv4";\r | |
118 | tmpaddr.sin_addr.s_addr = hdr.v2.addr.ip4.src_addr;\r | |
119 | inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip));\r | |
120 | @@ -323,6 +329,8 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0)\r | |
121 | proxy_external_port = tmpport;\r | |
122 | goto done;\r | |
123 | case 0x21: /* TCPv6 address type */\r | |
124 | + if (ret < 52)\r | |
125 | + goto proxyfail;\r | |
126 | iptype = US"IPv6";\r | |
127 | memmove(tmpaddr6.sin6_addr.s6_addr, hdr.v2.addr.ip6.src_addr, 16);\r | |
128 | inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6));\r | |
129 | @@ -381,10 +389,13 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0)\r | |
130 | goto proxyfail;\r | |
131 | ret += r2;\r | |
132 | \r | |
133 | + if(ret > 107)\r | |
134 | + goto proxyfail;\r | |
135 | + hdr.v1.line[ret] = 0;\r | |
136 | p = string_copy(hdr.v1.line);\r | |
137 | end = memchr(p, '\r', ret - 1);\r | |
138 | \r | |
139 | - if (!end || (end == (uschar*)&hdr + ret) || end[1] != '\n')\r | |
140 | + if (!end || end[1] != '\n')\r | |
141 | {\r | |
142 | DEBUG(D_receive) debug_printf("Partial or invalid PROXY header\n");\r | |
143 | goto proxyfail;\r | |
144 | \r | |
145 | -- \r | |
146 | ## subscription configuration (requires account):\r | |
147 | ## https://lists.exim.org/mailman3/postorius/lists/exim-dev.lists.exim.org/\r | |
148 | ## unsubscribe (doesn't require an account):\r | |
149 | ## exim-dev-unsubscribe@lists.exim.org\r | |
150 | ## Exim details at http://www.exim.org/\r | |
151 | ## Please use the Wiki with this list - http://wiki.exim.org/\r |