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

countermeasures to ALPACA attack? #5046

Open
lambdafu opened this issue Sep 19, 2024 · 7 comments · May be fixed by #5061
Open

countermeasures to ALPACA attack? #5046

lambdafu opened this issue Sep 19, 2024 · 7 comments · May be fixed by #5061
Assignees

Comments

@lambdafu
Copy link

Hi,

I am one of the authors of the ALPACA attack from 2021. I am currently revisiting the evaluated implementations to see how widespread our suggested countermeasures were. See the paper for details. In Table 4, we indicated that Cyrus IMAP 3.2.4 does not reject HTTP requests, allows an unlimited number of errors and has a reflection vector. We also indicate that Cyrus POP3 3.0.8 does not reject HTTP requests and allows an unlimited number of errors. In Table 5, we indicate that these versions of Cyrus were vulnerable for Download (IMAP and POP3) and Reflection (IMAP only) attacks. A reevaluation by Janik Hölling in 2022 found that Cyrus 3.4.2 behaved the same, and that it does not implement strict ALPN or SNI validation. You can find the exploits and docker container for the reevaluation in our artifacts.

I understand that sometimes Cyrus is used with a proxy server like Nginx. To my understanding, nginx implemented strict ALPN validation, so users of Cyrus who put it behind nginx might be fine without any changes in Cyrus.

However, for others, countermeasures native to Cyrus might be appreciated. Did you consider these countermeasures?

  • strict ALPN validation (i.e., reject connections from clients indicating that they want to speak HTTP or FTP instead of IMAP resp. POP3).
  • optional strict SNI validation (i.e., the SNI extension matches a configured hostname, requires a hostname to be configured in the server)
  • detect HTTP requests by GET/POST/etc verbs and "header: value" lines.
  • limit the number of tolerable errors to a small number (< 11, the shortest typical HTTP request header, )
  • remove reflection vector from command output, such as through the IMAP tag
* OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE STARTTLS AUTH=PLAIN SASL-IR] test Cyrus IMAP 3.2.4-Debian-3.2.4-3 server ready
<script></script> noop
<script></script> OK Completed

Thanks!

@elliefm elliefm self-assigned this Sep 20, 2024
@elliefm
Copy link
Contributor

elliefm commented Sep 20, 2024

Thanks for the report, I'm looking into it.

It's worth observing that, even though we do reflect limited html contents in an IMAP tag, we at least won't reflect one with a trivially useful payload, because () aren't valid in IMAP tags:

* OK [CAPABILITY IMAP4rev1 IMAP4rev2 AUTH=PLAIN AUTH=LOGIN ENABLE ID LITERAL+ SASL_IR] debian Cyrus IMAP 3.11.0-alpha0-891-ga30e9a7cd server ready
<script>attack()</script> noop
* BAD Invalid tag

@lambdafu
Copy link
Author

Thanks for looking into it! As for the payload, I'm not an expert, but if I google "xss bypass parenthesis" I get several pages with suggestions how to avoid parenthesis in XSS payloads. For example, this worked in courier:

<script>alert`XSS`</script> xxx

But I did not do extensive testing. Just wanted to point that out.

@elliefm
Copy link
Contributor

elliefm commented Sep 23, 2024

Sure, thanks, that's really appreciated. I did my own search and found a few interesting ways to inject a function call that from an untested visual examination I think would be valid tags according to the IMAP spec. So I'm thinking about violating the spec in order to be more restrictive in the tags we'll accept -- though that will take some care because I don't currently know what kinds of tags real IMAP clients are actually using.

So far I'm thinking of rejecting:

  • Tags containing <, >, :, maybe some carefully chosen others, perhaps even just any non-alphanumeric. This would prevent the reflections containing <script>, and trivially treat HTTP headers as invalid commands (which I anticipate combining with a limit on consecutive invalid commands, after which the connection is dropped)
  • Tags that are the strings POST, PUT, maybe some others -- any HTTP request method that takes a body I guess -- but these could cause seemingly random problems for hypothetical IMAP clients that use alphanumeric tags, which I don't know if those exist.

It also seems important to drop the connection outright if the first command has a tag of POST, PUT, etc. There's a couple of ways I can think of to approach that and I'm not yet sure which I prefer:

  • One way would be to special-case for those strings on only the first command, but those would be valid tags otherwise. That would have minimal impact to real IMAP clients, I think, but it would be extremely specific to HTTP clients.
  • Another way would be to make those strings invalid tags generally, and drop any connection whose first command contains any invalid tag. That would have a greater hypothetical impact on real IMAP clients who want to use those strings as tags, but could also go a long way towards rejecting other kinds of non-IMAP connections.

I suppose a way to limit the impact of rejecting POST/PUT on IMAP clients might be to only reject those tags if the command was also invalid. That'd catch stuff like POST / HTTP/1.1 but won't affect stuff like POST select inbox. I'm not sure if it's possible to trick a browser into sending something that looks like a valid IMAP command in the target resource field of an HTTP request... POST noop HTTP/1.1 would probably work and might be plausible, hmm. So actually, I think I've convinced myself we probably have to reject this tag regardless of whether the command was valid.

@lambdafu
Copy link
Author

Restricting tags and blocking HTTP requests are solid application layer countermeasures. If you limit the HTTP detection to the first command, I recommend to make sure that this works correctly with STARTTLS. For example, "Sendmail only detects
HTTP requests at the very start of a connection. If STARTTLS is used, the first command inside the connection can be
sent by the attacker, bypassing the detection" (Section 6.3 of our paper).

Note that strict ALPN validation is a strong countermeasure, as all common browsers already send ALPN identifiers like "http/1.1". The ALPN identifier "imap" is reserved for IMAP, so any client sending an ALPN extension that does not contain "imap" could be blocked. Then we don't even get to the application layer protocol.

@elliefm
Copy link
Contributor

elliefm commented Sep 25, 2024

Thanks, that's a good observation about STARTTLS, I'll keep it in mind. I don't know anything about ALPN, this issue was the first I heard of it, but I'll have a look into that too.

@elliefm elliefm linked a pull request Oct 2, 2024 that will close this issue
@elliefm
Copy link
Contributor

elliefm commented Oct 2, 2024

I've had a skim of the Wikipedia article on ALPN, and the OpenSSL docs for using it. It seems reasonable to implement, but we'd probably tackle it as a separate PR, and implement it for all protocols we implement, ingoing and outgoing, in one fell swoop. So implementation of that might lag somewhat behind the basic mitigations I'm already adding.

@elliefm
Copy link
Contributor

elliefm commented Oct 15, 2024

#5087 makes all our service daemons perform ALPN negotiations when handling client connections (httpd already did this, now the rest do too). We don't yet have anything for connections where cyrus is the client, but getting one side done is a start!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants