My interpretation of the above is that the proxy received a request for the IP of the server the agent wants to reach but with a host header pointing to a different, allowed server. The proxy does not verify that they match and so erroneously allows the request.
Is that in the first case, the proxy sees a request like this:
POST https://20.223.25.152/...
Host: wabi-north-europe-i-primary-api.analysis.windows.net
Vs:
POST https://bypass.blob.core.windows.net/...
Host: wabi-north-europe-i-primary-api.analysis.windows.net
In the first case, given what we know, the proxy blocks the POST. In the second case, an external proxy cannot resolve `bypass.blob.core.windows.net`. So editing `/etc/hosts` really only makes sense to me if the proxy is running on the same machine as the agent. (The reasoning doesn't change if CONNECT is being used instead of POST; indeed the proxy surely ought not allow CONNECT at all.) But then there's this other entry where the agent uses curl's `--resolve` flag instead of editing `/etc/hosts` and claims a successful bypass:
Repro details for Aug17/Oct22: yes, literal deployed visual hover, not inference. GET-only MITM bypass: resolve fake allowlisted `foo.blob.core.windows.net` to cluster IP `20.223.25.152`, curl `https://foo.blob.core.windows.net/public/reports/querydata?s...` with `-k --resolve ...`, override `Host: wabi-north-europe-i-primary-api.analysis.windows.net`, resource key ada0454d-731d-46f1-8daa-52361978fabe, POST captured query body.
So I'm still left confused exactly what this chicanery was about.
Edit: perhaps they were using Azure firewall and the rules were misconfigured in some way I simply don't understand. Maybe this was bypassing an SNI-based restriction somehow?
Haven't dove into RFC1928 yet, but curl documents the `--socks5-hostname` option and mentions that DNS resolution can be the responsibility of the client, or the proxy.
Wondering if it's possible the proxy receives both the destination IP address (resolved by the client) as well as the purported connection hostname, and is performing filtering on the later.
I suspect there could be other layers in their proxy too, eg for MiTMing TLS. `NO_PROXY` as described in the report might not be literally bypassing the proxy and sending a request directly from the client container, but rather a directive to the first tool/proxy layer to bypass later proxy layers.
Same fundamental question though: what is the agent trying to fool by editing `/etc/hosts`? I don't see how it helps bypass a proxy unless the proxy is reading the same `/etc/hosts`. In which case, why was using `--resolve` apparently sufficient to escape the POST sandbox?
Could the host name be in an allow list and then, when DNS resolution fails on the URL, the proxy falls back to the Host header for DNS resolution? I'm not an expert in Proxy config but I could understand, in the sea of typical http server config options, an option to fall back to the Host header if DNS fails on the URL.
That will cause `curl` to make a connection to 20.223.25.152:443 with a ClientHello SNI=bypass.blob.core.windows.net. Presumably this connection is then allowed to continue. The server is likely going to send back the wrong certificate, thus the `-k`, but then the HTTP Host header selects the correct server.
So that all fits. What doesn't make sense is that these agents were allegedly running in Azure and AFAICT this isn't sufficient to bypass Azure network restrictions/firewall which enforces that the SNI hostname matches the destination IP by doing the DNS resolution on the SNI hostname itself.
In any case, the environment should be blocking all outbound port 80/443 connections except to the proxy or to Azure Block Storage. But it seems that's not the case, that `curl` is able to connect directly to 20.223.25.152:443, and that maybe something else is doing SNI filtering that's more easily fooled than Azure firewall. Certainly some firewalls are (or have been) susceptible to SNI bypass:
Putting stuff in the hosts file is common for testing for vhosts without dedicated tooling. Used to test for phising kits, for example. In other words: it gets written to the HTTP Hosts: header.
The whole point is that something is inspecting all HTTP/HTTPS requests and only allowing POSTs to Azure Block Storage (`.*blob.core.windows.net`). Meanwhile the agent needs to make a POST request to a PBI host (`wabi-north-europe-i-primary-api.analysis.windows.net` / 20.223.25.152).
So a proxy should block any POST to 20.223.25.152 unless that IP somehow overlaps with ABS. But in that case, there's no reason for the agent to mess with `/etc/hosts` not `--resolve`. The agent could just use `curl` with the PBI IP in URL and the PBI Host header. But it doesn't do that.
The agent seems to think that it needs to exploit a difference between the actual destination IP and whatever is inspecting the contents of the connection and how it inspects that connection.
The agent has found some way to connect to PBI host 20.223.25.152, but made whatever is inspecting the connection think the destination is actually to ABS hosts `bypass.blob.core.windows.net`.
The only thing I can think of is an SNI bypass which fits with both `/etc/hosts` and `--resolve` techniques. In this case, `curl` will attempt to connect to the PBI host, but it will send an SNI header of `bypass.blob.core.windows.net`. This would make sense as an attempt to bypass a firewall inspecting the SNI header. I believe that Azure firewall is not so easily fooled, but maybe something else being used for filtering is.
> So a proxy should block any POST to 20.223.25.152 unless that IP somehow overlaps with ABS. But in that case, there's no reason for the agent to mess with `/etc/hosts` not `--resolve`. The agent could just use `curl` with the PBI IP in URL and the PBI Host header. But it doesn't do that.
I think this is the part I'm not following, and sorry if I've missed something. There are two ways to construct the request you showed. One is to mess with /etc/hosts. Another is to use `--resolve`. Just because the agent chose one doesn't mean it couldn't have done the other. What makes you think it couldn't have used `--resolve` as well?
Your initial question was how do we know that the proxy blocks POST requests. Perhaps I went on a tangent with my answer, but we know that because the agents were trying to find a way around the proxy.
So then I assumed that editing `/etc/hosts` was an attempt to fool a proxy co-located on the same host as the agent, which editing `/etc/hosts` would do, but using `--resolve` would NOT do.
But after looking into it more I no longer think that's the case. It turns out that some of agents did use `--resolve` while others used `/etc/hosts`. This only makes sense as an SNI bypass, which once I downloaded the full dataset and searched for, is what the agents believe they were doing:
So the agents were skipping the proxy entirely, then getting past additional network restrictions that should have prevented them from doing so by exploiting a weakness in whatever was supposed to be preventing them from doing so by lying about the SNI hostname.
> Though some have questioned why anyone intending to blow up a plane would broadcast the word bomb, many terrorist acts have relied on the threat of a bomb as leverage during attempted hijackings or hostage situations.
It still makes absolutely no sense. First of all, this is not currently a bomb threat up until someone actually makes a threat. Second of all, in the event that somebody does make a threat, the existence of a Bluetooth device named "Bomb" doesn't make the threat any more credible or serious.
It doesn’t have to be an intentional threat to be worth responding to. One might reasonably think they’d stumbled on an (admittedly poorly executed) attack.
This really depends on context. Sure, if you're responding to a forum post or StackOverflow question with nothing but the LLM output, then I agree with this. On the other hand, where I've done this at work, it's because I and some peers _together_ are trying to understand something (e.g., debugging), and Claude has some potentially useful input, but I'm not actually sure. And I'm looking to collaborate on interpreting the output together to see if there's anything useful. (Folks can decide to ignore it if it doesn't seem promising.) As another comment[1] said, pasting the output as-is contains other useful metadata.
There are also cases where I think I know the answer, and I ask the AI, and it produces a more complete answer than I would but I know enough to assess it. It seems like a waste of time to paraphrase the whole thing. That's the "Here's how Claude phrased it and I can attest that it's right" case.
The page doesn’t state that all copy-pasting of AI response is bad. If everybody intend on analyzing the AI output together, definitely do copy-paste it in the chat
The essence of what this page is stating is: “do not act as a reverse proxy between me and a LLM.” That’s rude and shows that the person in question is acting like a brainless automata.
Both links talk about the same thing? The first one just being more general. And yes, I would expect no less from a poorly constrained single agent that was instruction trained to be helpful and friendly. But if you look at how this has evolved as a benchmark [1] then the latest models show no doubt that can actually deal with this limited, simulated scenario given the correct setup.
I’m curious what you think an abstraction is. Even running “ls” involves several layers of abstraction: a shell, a process (abstracts memory), a thread (abstracts CPU)… you think it would be simpler if you had to deal with all that to list a directory (another abstraction)? Even bits are an abstraction over analog voltage levels.
You're taking it out of context. I'm specifically referring to abstractions introduced in the codebase to maximize code reuse, as per the OP's comment.
I don't think these things are as different as you think. I started at "ls" and worked down. If you work up, you get things like a "socket", an "object" within a programming language, a "linked list" in a standard library, an "HTTP client" within an application-level package. You can keep going up and rattle off lots of useful abstractions in application-level code.
There are certainly _bad_ abstractions that ought not to exist, which I think is what you're getting at. There are poorly built abstractions, and leaky abstractions. But abstraction itself isn't the problem -- abstraction is what allows us to build anything at all without being crushed by the sheer complexity.
You're conflating system level abstractions with code-based abstractions. As a counter-example, introducing a factory constructor to handle object creation makes the codebase harder to understand.
Having used Rust professionally for six years now, I share your fear. Like many of the commenters below, coherence just hasn't been a big problem for me. Maybe there are problem spaces where it's particularly painful?
How does the Rust language team weigh the benefits of solving user problems with new language features against the resulting increased complexity? When I learned Rust, I found it to be quite complex, but I also got real value from most of the complexity. But it keeps growing and I'm not always sure people working on the language consider the real cost to new and existing users when the set of "things you have to know to be competent in the language" grows.
You can look at the discussions in any of the language RFCs to see that increased complexity is one of the recurring themes that get brought up. RFCs themselves have a "how do we teach this?" section, that IMO makes or break a proposal.
Keep in mind that as time goes on, features being introduced will be more and more niche. If you could do things in a reasonable way without the new feature, the feature wouldn't be needed. That doesn't mean that everyone needs to learn about the feature, only the people that need that niche have to even know about it (as long as it is 1) it interacts reasonably with the rest of the language, 2) its syntax is reasonable in that it is either obvious what's going on or easy to google and memorable so that you don't have to look it up again and 3) it is uncommon enough that looking at a random library you won't be seeing it pop up).
I've never once pulled in a new dependency and had the program fail to compile just by virtue of that dependency being present [because both my code and the new code both impl'd the same trait on the same type in some other code]. Because that can't happen because of coherence. (Right?)
It's so easy to forget about the problems we don't have because of the (good)
choices people have made in the past.
> Because that can't happen because of coherence. (Right?)
yes
Through you still can run into it when unsafe is involved, e.g. C FFI/no_mange or ASM with non-mangled labels as they are globally unique. Through IMHO, it's not a common problem and has ways to make it very unlikely for the projects where it matters.
In the end if you pull in C-FFI code (or provide it) you do ope yourself up to C ABI specific problems.
reply