
So, I'm Sophia. I'm going to talk to you about HTTP header injections, a splitting headache. So, really my title should mention request splitting, but I wasn't able to make as good of a pun using that. So, header injections it is. We will talk about that as well. Uh, a couple of words about myself. So I uh started out doing a PhD in pure maths. Luckily I came to my senses and realized that academia was not the place to be definitely not in pure maths. Uh so I instead worked uh three years as a developer at Cisco where I was working on the operating system which runs on the like carrier grid routers around the world. Uh and then eventually I made my
way over to security testing and pent testing which I've been doing for two years now. Currently I'm at binary security. um kind of a rough outline of what I'm going to talk to you about today. Uh so I like covering my basis. So I'll go through kind of the basics of the vulnerability we're going to be talking about first. Then I'll show you a demo of how things actually function. Uh then I'll be talking about hunting for this v vulnerability in the wild. Show you a real world demo and then talk a bit about things in Azure. Um if you know all of this very well from before, the first bit might be boring. You can then
wake up for the first demo. uh if you were present at seekitat festivon in August where I gave a slightly shorter version of the same talk then you can wake up around the second demo. All right so let's start from the beginning with a typical HTTP request. Uh so this is what happens if I in Firefox I go to binary security.no and I click the about tab. My browser will send this HTTP request. Uh now some of these headers and things are a bit long and annoying. So I'm just going to shorten that a bit and say that this is what the request looked like. It's essentially the same thing. Uh, so the first thing we need to
understand is what's up with these funny symbols at the end of the lines. Um, so this back slash r/n business is what we refer to as CRLF. Uh, so it's two control characters. The first one is referred to as carriage return and the second is the line feed shortened as CR and LF respectively or CRLF for the combination. Um, so if you use for example Windows, you might recognize this as the like this is the way to make a new line in Windows text documents. Uh, this is also the way HTTP version 1.1 has decided you delimmit the different parts of the request. Uh, so to make it clear what's happening, uh, I'll always explicitly write out the
CRLFS in my requests, but I'll also have a visual new line uh, to make it easier to read for us humans. Okay. Uh, with that out of the way, here's our HTTP request. Again the first line is what we refer to as the request line. Uh it has three parts. The first is the HTTP method which in this case is get and that tells us so that could be get, post, delete, uh whatever and tells you what you're doing basically. The second part is the path we are trying to access the resource. So in this case the about page and the third part is the protocol version. Uh so for the purpose of this talk, we'll always be dealing with HTTP
version 1.1 because HTTP version 2 does uh header things very differently and is not vulnerable to the attack we're talking about today. Uh luckily for us, most of the internet still lives in 2015 or whatever and does HTTP version 1.1. Okay. Then we have these four lines uh which are what we refer to as HTTP headers. Uh so each header has two parts. It has a name and then a colon and then a value. Uh and the way you end one header name value pan start the next is with this CRLF character sequence. Uh I didn't say but the reason why I write that as back slash rback slashn uh is because in most programming languages
that is the escape sequence to actually make these control characters. Um and then finally when you are done with all your HTTP headers you have this single blank line if you will or just a single crlf uh which signifies that we are done with the HTTP header section. Uh, now in some requests you'll also expect to see a HTTP body after the header section, but for this talk we only ever really care about the headers. So let's pretend like once you finish the HTTP header section, you're done with the request. Okay, so with that out of the way, we do need to say a few more words about HTTP headers. Uh, so the header name, that's
the thing before the colon, may consist of any printable ASKI character except for white space and the characters in this list here. So like brackets and things. Um the value has slightly fewer restrictions. So it may basically be any non-control ASKI character. Uh notably both CR and LF these special control characters are banned in both of these two. So both in the name and the value. And if you stop and think about it for it for a second, it kind of has to be like this because if the delimination the way I delimmit one header name value pair and start the next is with CRLF, then things would be highly ambiguous. If I suddenly can have CRLF within the
value itself, I wouldn't be able to distinguish that. Um, there's a slight asterisk here which is there this concept of line continuations, but that we we won't deal with that today. Uh, right. So, anyone who's ever read a specification or RSC or, you know, been given instructions, this is how it should work and tried to implement it knows that no one ever implements anything correctly. Uh, maybe a slight exaggeration there. So let's instead take a look at what happens if I have an HTTP client or server which doesn't follow these rules properly. Uh so here is a highly constructed example where I have a server which is planning on making the following HTTP request. So
I'm going to get the about page on binary security uh and I'm going to include a HTTP header named some header with a user controllable value whatever that means. So me as the user, the malicious user here figures out I'm going to go and see what happens if I try to send CRLF characters into this header value. So I might try inputting a value like this. So a value of blah. I then insert the CRLF characters and then something which looks like a another valid header name value p. If I just input this straight in in place of the user controllable value placeholder here, this will look something like the following. Um, so again I've added
visual new line to make it really obvious what's happening here. It's the CRLFS themselves which actually determine that you've started a new header name value path. Uh, and what actually happens here is that you've injected a whole new header which the server didn't intend to include originally. Uh, but we don't need to stop that. We can actually take this one one step further. Instead of injecting just the header, let's inject a whole request. Uh, so returning to the same example, let's try inputting something like this. So again let's have a value of blah. We have a CRLF to terminate that header name value path and then we have another CRLF which is like the end of the
request itself followed by something which looks like a second well-formed HTTP request. So again inputting things and adding some visual new lines to make it more legible and actually we can make it even more clear what's happening by adding a bit of space here. Uh and what we see is that we end up with actually two completely valid HTTP requests. The second request which is getting the smuggled resource is what we would refer to as the uh a request a smuggled request or like request splitting. So we had a server here who intended to make a single request. Me the malicious user made it make two requests instead. Um with that out of the way we are ready
for our first demo. Um so I've written a bit what's going on here but we don't actually need to read that. That's just back up in case of technical issues. Uh okay. So on the right hand side here I have a terminal where I've sshed to a server um put up in the quickest and dirtest way possible which is hosting various uh hosts. Um let's see if we have some access logs. So the first page we have is uh an internal site which on the left hand side I'm trying to access this internal site from the internet. On the right hand side, I can see from access logs that okay, here's my IP if anyone
wants to know it. Uh it's trying to get this resource and that returns a status code of 403 forbidden which is what we also see on the left hand side. Uh this was expected because this internal site is meant as like a resource you can only reach from local host itself on the server. Uh so to make things more interesting, we have a second host as well. So that will be I have it here. Nice. Let's see. um this page called basic demo. Um so to see what's going on there, we need to look at some different logs. Let's see, let's try that again. Um so here we see I'm accessing this page. Uh I'm getting the root resource and
returning a status code of 200. Okay. Uh and what this is actually doing under the covers when I talk to basic demo what it's going to do is it's going to ping an internal uh status page on the not ping it's going to get an internal status page uh from this internal site and then it's going to give the uh the return code back to me the end user. So this got 200 okay back from the internal resource. Uh to see what that looks like we go back to the access logs for the internal site and we see here that that's coming requests from local host itself. Uh now this is going to get mighty
confusing if we can't actually see the requests on the headers which are going in and out here. So uh I've attempted to do some bash magic and we'll see if this works. So if I now visit basic site uh basic demos site then I get to see the requests which are made. So the first request being made here that's the one I'm making from the outside here to basic demo. with all the HTTP headers my browser is adding for it and then that is internally making a secondary request to the status.html page of this internal site. Uh now this in itself is not terribly interesting. We need some more ingredients for anything to happen here.
So this page also actually takes a query parameter. Um I think that's going to break. Let's see. Let's try doing like that. Uh so this takes a second parameter sorry a parameter called name and what it's going to do when I make this request with name equals Sophia is in the secondary request it's going to append this custom header named Xcustom name header. Let me put that high up just in case. Uh so we have this custom header here with a value of Sophia. Okay. Okay, so as the malicious users we are um this is a prime target for attempting CRLF injection because what I can see is that as the end user I'm inputting user controllable value here
on the left hand side in the browser and what's happening is that the server which I'm talking to is going to input my value into request it's making uh so let's attempt to do CRLF injection. Uh so what I would want to do is input something like the following. Uh I don't know if you guys can see that at the back. Let's lift that guy up. So I basically want a value of like Sophia and then a CRLF and then something else which looks like a valid header. Uh to actually input this we need to URL URL encode things. So I've uh cheated because I will typo that. See if we manage. Um so let's bring that guy up
again if I can. Uh so here is the request I'm making from the outside. Here is the secondary request being made to internal. we have the Xcustom name header and we also have an injected header with a value of it works. Okay, so that is HTTP header injection in practice. Um, next of course as predicted we will now do uh full request smuggling or request splitting. So what we now want to do is something like the following input a value CRLF to end that header CRLF to end the whole request and then a second thing which looks like a fully formed uh HTTP request. So, copying that, we end up with moment of truth. Let's
see it. Here is the first request I made. Here is the expected status request. But that is a third rogue request down here to the page admin.html on the internal site. Uh, so this is the smuggled request in this case. And to prove to you that this isn't just my logs which are badly formatted, we can go back to the access logs for the internal site. And we see that indeed two actual requests are made here. One to the status page and one to the admin page below. All right. So you are now all experts on uh request splitting through CRLF injection. You can do request splitting in many other ways as well. This is just one of many. Um I've
shown you how to do this but I haven't actually told you why this is a security vulnerability as opposed to just a stupid bug. Uh so we should talk a bit about impact. So the setup here is the following. We have a server which intends to make a single request but the attacker causes it to make multiple. That's kind of the very high level view of what's going on. Uh so what can we do with that? Well, first of all, we can use it to bypass internal access controls. Uh so actually we did exactly that in this first demo because the internal site wasn't actually reachable from the internet. It was only reachable from local host. But
because my second request was being made by the server itself, it was able to talk to the internal site. Um, equally there's not really any reason why this uh internal site needed to be reachable on the internet at all. That was just so I could show you it existed. Uh, really you'd put it on like an internal IP, right? Uh, but you can still reach it from uh the server itself which is making the requests. Uh, the second thing you might be able to do is bypass client authentication. Uh so in the typical kind of modern world of complicated web applications and things, you'll have you know some kind of load balancer which is talking
to a bunch of internal hosts which are all talking to each other and everyone is doing stuff. Um and what you'll commonly see is that for the internal services to talk to each other they'll include some kind of authorization. So let's say an authorization header in the HTTP requests. Now me from the outside does not know the key that the internal services use to talk to each other. But if I go via the server which is planning on making this request, it would it will itself add the appropriate keys and I'll be able to talk to resources which I wouldn't necessarily be able to communicate with otherwise. Uh if you're really lucky here, there's something
internal which allows like recording the request which came in. So let's say there's some kind of comment functionality. What I do is I go and split a request I'm making in such a way that all headers which would be added by the server go into the body and then get put in a comment. Then I go and read the comment and I see, oh cool, it's adding this authorization header and I've leaked out the keys from the server. Um, next. So I haven't really spoken about the limitations of this type of request splitting. So um, I'm slightly limited in what hosts I can actually talk to because my request is going through the same HTTP connection as the previous
one. Like I'm not making two entirely separate requests. So I can't just go to like google.com. I have to speak to the same host as the first one. uh same like physical whatever doesn't matter. Uh but if you have something internal which allows some kind of redirect then you can combine that. So you do your your smuggled request goes to something which allows you to then redirect to the resource you actually want and you might be able to escalate this into basically a full serverside request forgery. Um so hopefully I've convinced you that um this is a real vulnerability. Now let's forget about what you actually do with it and go back to the theoretical
side. Uh, not really. We're actually going to do something, but okay. So, here's the plan. Let's go and pick something really specific in code. So, like in source code that allows CRLF injections, by which I mean, let's go and pick some common pattern of vulnerable code, which which people do. Uh, so if you can do CRLF injections, you can also do header injections and request splitting as we just saw. I mean, you might be able to at least. And then what we're going to do is we're going to search through all open source repositories and packages and whatever we find out in the world and we're going to see do we find lots of bugs and then
we are going to become famous or speak at bides or both. Okay, here's the vulnerable code. Uh so from this point onwards we have specialized to C sharp because um why give yourself too broad of a scope, right? Uh, and the code you can see up on the screen here is actually the code which is used for the endpoint in my basic demo site which you saw uh a little while ago. Um, this isn't terribly interesting. It's just defining a a URI it's going to talk to for the status endpoint. It's going to talk to it and then it sends the status code back to the end user. The only interesting bit here is that if
statements kind of around the middle uh which is saying that if uh you've specified the name query parameter, I want to add this extra xcustom name header. And how do we do that? We do it with a method named try add without validation. Uh so what's happening here? You have a request object in C that has a headers object attached to it. And the way to add headers, there's various ways. One of them is by using this method which takes a name and a value. So in this case, the name of the header is the X custom name header, and the value is ironically called name. I should probably have picked something else. Um, and in a completely shocking turn of
events, triad without validation does not do validation. Um, that's not entirely true. It actually validates the name properly. It's just the the second parameter here. It's like, yeah, yeah, give me any control characters you want. I'll just kindly append it to my request. I might end up making multiple requests. I don't care. I'll just ship it out for you. That's all right. Um, conveniently, try ad without validation is quite a long and not it doesn't really roll off the tongue. So, I don't expect if I go searching for this to find lots of false positives of other people implementing functions called triad without validation and then I have to filter out. They're like, "Oh, no, that's some custom function." Like,
I expect it to 99% of the time be the real uh C function. I mean, like the net library function I'm hitting. Okay, let's go searching GitHub. Um, if you search on GitHub for the string triad without validation and you filter on C# code, then there are roughly 20,000 hits. These are spread across 4 and a half thousand unique repositories. Um, so people do use this shockingly. I initially I didn't really understand why anyone would use this method, but that's another topic I guess. Um, also in the world of C and .NET, we actually have access to much more open source stuff because if you have a binary, you can just trivially decompile it essentially.
So let's also go and have a look at public nuet packages. So for those not super familiar with C# and net is like the main package manager. Um first of all there's something like 700,000 publicly available Nougat packages. You are able to get some like metadata and stuff for them. A lot of these are old. This has existed for a while. So for like 380,000 of them you get like updated metadata and stuff like download counts. And I figured anything which doesn't fall in this category will probably be I I don't need to look at that. Um so out of these I sorted on number of downloads and I looked at the 5,000 most popular public
Nougat packages downloaded each of them decompiled them and then did a string search for triad without validation. And out of these there were 121 packages with hits. Uh so I haven't written the number but there's multiple hits per package here as well. So you end up with individual hits more than that but 121 unique packages. Also, there's quite a bit of overlap between these packages and the GitHub repos because a lot of this is open source. All right, out of this I checked something like 80 GitHub repositories and all 121 Nougat hits for a total of 200 different code bases. Um, that sounds worse than it is because a lot of these you can just immediately say no,
this isn't going to be vulnerable because it's just like hard-coded strings being input, for example. That's very easy to exclude. Okay, but you would hope that with all of these numbers, I do like numbers, uh we actually did find something interesting. Over to the results, I've grouped these into various categories. Uh the first one is a bit sad um or not that interesting and that is command line applications. Uh so we have the scenario where someone has written a command line application that takes some kind of command line arguments uh and those arguments are somehow passed through and end up in triad without validation. So that means if you in the command line give these
control characters then you'll end up doing like request splitting or whatever. Um the kind of fundamental problem with this is that if I'm running a command line application on my machine, it's my machine I'm tricking to make the second request. Now I don't need to do that. I can just go to my browser and make the request I was planning on doing. Uh so this is kind of not all that interesting. Um there is an asterisk on that which is of course someone else might have gone and written a web server which takes some user input and then on the back end they go and call this command line uh application with my user controllable input from the
web and then suddenly I'm doing request splitting on the server again. Uh now aside from the fact that that is painful to search for I also figured that if you are in this scenario you are probably able to do worse things like actual command injection. So this is not like the main area to look at. So I've kind of just discounted all of these and just said yeah not interesting. We have a second even sadder category. Um so you'd think that by sorting both GitHub results and Nougat results on like number of downloads or number of forks, number of stars, whatever metric you have, you'd only be looking at interesting packages or repos. Turns out
Nugit has a lot of ancient packages with a lot of downloads. So you can have like packages which haven't been touched since 2016 which reach this like top 5,000 download count uh and are like full of vulnerabilities and it's like okay there's literally no one on the internet who uses this package anymore. It is fully deprecated and removed. Um so initially I got really excited about a couple of results in this category and then realized damn this is no one's ever going to use this. Okay, moving on. And then we have something a bit more interesting. Um so we have the category of APIs and libraries which expose vulnerable methods. So what I mean by
that is I've gone and written some library or package which is going to help you do something else and I have a public API. So I say use this method to do my thing but under the covers I take the input you give to my API goes and ends up in triad without validation. So now we've kind of got one step removed from triad without validation itself and now it's my API which is vulnerable. Um, with triad without validation itself, it's kind of obvious from the name that you aren't being validated. But if I have made something like an add header method, it's suddenly not so obvious anymore that you are vulnerable. So we have two examples here. We have the uh
package restar and refit. Uh so perhaps ironically both of these are trying to do exactly the same thing which is uh they are both libraries which are attempting to simplify interacting with REST APIs. Now there's a lot of packages doing this inn net. I don't know if people really struggle with interacting with REST APIs or what's up here but uh okay I won't judge. Um and then we have a final category which is Microsoft and Azure SDKs. Um this is a bit painful because well first of all anyone who's read Microsoft code this is painful. Uh second of all in depending on how your nu get packaging is done very often other nuet packages will pull in some of these
azure and Microsoft libraries and then I'll get a bunch of false positives because you get hits for triad without validation in every single Microsoft SDK and then it's pulled into every single package and then you get much more hits than you should have got. So out of those 5,000 top packages where you had 121 hits that is not actually the real number. That's probably like 20 real hits down. hund of them is just Microsoft showing up again and again and again. Okay, let's talk about rest. Uh so this is a screenshot from their own uh web page. In their own words, rest chop is a simple rest and HTTP API client fornet. We'll go and have a look at their
documentation and see how am I supposed to add a header to a request. Um so this is the documentation. Don't know if you can see it at the back but essentially they give you three or four different ways to add a header to a request. Um and they have an example line here in the middle which says so what you do is you make a rest request define a path and then you use this method called add header which takes two arguments a name and a value and then that adds the header. Simple enough. Let's do a demo. Uh so here is the code which is running in the next demo. I have another host
running on my demo server um which has this get async endpoint and what it does is it takes a query parameter named key and it goes and puts it into this rest chart method named add header. Uh so the line with the second highlight here is essentially identical to the line from the documentation like I haven't done something dumb on purpose here other than putting user controllable input into it. Uh, so let's see. Um, we probably want that window. Let's clear it. And we want Nice. We have it. Uh, so here is my beautiful rest example. It has this endpoint to check the server status. I messed up because it takes a key parameter. Let me just hang on. Um,
okay. Uh so this is this code is doing the exact same thing as my other demo just it's using the rest sharp library to do it instead of my own badly written C# code. Um, so looking at the requests coming in on the right hand side here, we see I'm making a request to the server at this get async endpoint. And then the server is making a secondary internal request to internal.site/stml and it is including this uh custom header X key with a name of high, not a name, a value of high. Okay, we know what's going to happen. We are going to attempt CRLF injection. Uh, we're going to use exactly the same payloads as we
had previously. Um, so I'll just paste that in URL encoded. And for the second case, so here's my initial request. Here's my second one. We have a key of Sophia. That should probably be something else like key. And we have an injected header with a value of it works. Let me put that high up. Uh, cool. Let's do the full request smuggling. Let's see if we have it here. Yep. So again, I'm going to use the exact same example as we had previously. Here the payload is literally identical. And what do we end up with? We end up with the first request, the second intended request, and the third smuggled request to admin.html. Okay. Uh now what's bad here is that is
no way in rest to add a header to an HTTP call without being vulnerable to this. So there's there's like no safe header methods in this library. Um, now you can say that you can argue that like, yeah, but just don't put malicious stuff into my API and I won't do bad things, which I can see that point. Uh, so initially when I found this, I was a bit like, what doesn't really do here? I haven't actually found any proper vulnerable uses of this. I did a bunch of searching on GitHub for other people then using rests methods. found some new libraries which then are vulnerable and had to start searching for does anyone use this library and it all became very
painful and I didn't have like a really clean example of here's someone who's vulnerable because of you guys. Um I did mention possibly that I gave a similar talk at Sikid Festival in August uh slightly shorter than this one where I showed this same demo and then I figured okay now that I've spoken about this I should probably actually report it uh which I did and then ironically it turns out they did take it seriously so that got a CV. Um so I guess I accidentally dropped a zero day at my last talk. We'll see if there any accidental zero days today. I I think probably not but we'll see. Uh and they also fixed it
pretty much immediately and it is fixed from rest version 112 onwards. Um side note what is going on with the rest job versioning numbering. I don't know how you have 112 major versions. Uh yeah so 111 and previous are vulnerable and the demo was done in version 111. Uh let me just check the time. Okay let's have a look at refit as well. So refit in my own words again is an automatic type- safe rest library for net core zamarind and net uh sounds very similar to the description of rest chop and indeed it's trying to solve the exact same problem. So I won't do a demo of this because it's like pretty much identical but I'll show you what the
code would look like in the refit case. Um this I also reported at the same time as rest. Um they eventually got round to doing a fix which they've pushed to the main branch. They haven't released it, but it's been there for like a month. Um, I posted this comment two weeks ago on the GitHub uh security report thingy, whatever it's called. Um, they haven't answered. I don't know if they plan on doing anything or if they plan on actually like making a new release, but who knows? For the time being, don't use refit for anything critical, I guess. All right. Now, over to something fun. Let's talk about Azure. Um so the Azure SDK that's so uh that is uh there's an
Azure SDK for like all the big programming languages and the idea is to help you when you are writing your code to interact with Azure resources and management and whatnot. Uh in the net case this is open source I guess it is for most languages. Uh and the repo is called Azure SDK for net. Uh because this whole thing started with doing like a code search we of course going to do a code search. Um, to the surprise of no one who has looked at Microsoft before, this repo is massive and there are 1,400 results for this term uh spread across 84 files. Now, I did look at more results than this initially, but they
were way quicker to look at because you have smaller code bases. You have a lot of uh false hits which are easy to exclude. Looking at any one of these is an absolute pain to follow through and see like what code actually ends up inside this method. Um, so I had to learn how to use better tools. So enter CodeQL. CodeQL is a semantic code analysis tool which means that uh I guess you hook it into your build system and it has like actual knowledge of how your code actually works, what talks to what, what belongs together, that kind of thing. That's not a good explanation. Um but what's useful here is that it has a
concept of sources, syncs, and flows. So what I mean by that is a source um in my case will be basically any argument to a public method in a public class aka a public API. Uh and a sync is going to be the second argument to try add without validation i.e. the thing which is the value which is vulnerable to uh crlf injection. This is my attempt at writing the codeql code for the sync. Uh this is the first time I actually wrote any codeql. So this might be completely wrong but it did do what it was supposed to do. Um and then the idea with flows here is that uh what code does for you
is if you've defined the source and the sync it will tell you all the sources and syncs which link up together. So it says like if you start with this argument in this API then it goes into this parameter which is put into this function call which is put into this function call which defines this new attribute which goes into this function call which eventually ends up in triad without validation second argument. So CodeQL is much better doing this than I am manually. What did we find? Uh we found various things. So first of all um there are 19 public methods. So in the public like API of the Azure.NET SDK which take an argument named custom
headers. Uh so custom headers is what it sounds like. It's a dictionary mapping a header name to a list of header values which are supposed to be added to some requests. There also 10 public methods which take an argument named if match which is put into a header of the same name and six public methods which take an argument named XMS snapshot which is put into a header of the same name. And unsurprisingly because it is at this talk all of these are vulnerable to CRLF injection. Um that sounds you know pretty bad. It's like what 35 vulnerable methods that doesn't sound great. Uh, so I figured all right, I'm going out on the internet. I'm going to find everyone
who's using this and I'm going to just like hack everyone. Uh, we have lots of vulnerable APIs. No one uses any of these APIs. Uh, nobody. So, I haven't actually checked absolutely everything. The, you know, uh, slight asterics there. But what's going on here? So, here's an example which it's unclear if you can actually read. Uh, on the left hand side is the code from the SDK repository. uh one of these vulnerable methods which is named get immutability policy with HTTP messages async takes an argument named custom headers which is vulnerable uh the code is on the left on the right hand side is the Google search for the name of this method with with the quotes
that's exactly one hit on Google which is the Microsoft.NET uh sorry the the Microsoft learn documentation for this method um side note that should be more hits because this is on GitHub but I don't know how Google works apparently. Um, so if you actually click into this Microsoft learn article, you realize that this is a part of the legacy API. And indeed, looking at a few more methods, they are all within the legacy API. Now, some of them are seem to be more common than this one. I took like the least useful one on purpose because I've I've learned from dropping zero previously. You have to be a tiny bit careful. Um, so yeah, if you go into the
documentation, you see this uh Azure SDK fornet legacy banner. Um, but I still didn't quite understand what was going on here in particular. What is up with these custom headers? Like if I'm trying to, I don't know, I'm going to upload a file to my Azure container. When do you ever need custom headers? Like what is the use case of this? So I tried to do a bit of Googling and also I noticed that all the methods which took this custom headers argument had a name which was something something something with HTTP messages async which is a very specific kind of suffix. the first hit on Google for searching just what is with HTTP messages async is someone
asking my exact question on the repository I'm looking at um this issue has been closed that was not a satisfactory explanation in that so I still didn't quite understand what was going on further searching there's a bunch of like uh stack exchange stack overflow things where people ask basically the same question uh I don't know if you couldn't you definitely can't read that one but here someone's asking for specifically the uh Microsoft Azure face API they're saying There's a method named get async and a message named get with HTTP messages async. Why do both exist and what is going on? No good answers. Searching a bit more and eventually things pointed me to this second repository named auto rest. So
the author rest repository also lives in the Azure organization on GitHub. Uh and actually looking a bit closer at the SDK repository, what's happened here is that all of the vulnerable code I found has been generated by this author tool. uh the author rest tool goes and gets the rest specification from a yet a third library uh repository I'm in and then it goes and generates it and checks it out to the SDK library. Um so my hypothesis here was oh right so it's the author rest thing which is generating vulnerable methods. I went and looked in that repository I found some like example output which had tried without validation which was vulnerable. I'm like oh yes nice I'm getting it. I rerun
like generate that same example and it's not vulnerable. So what's happened is there's an older version of author which generates vulnerable code. It does not do it anymore. Uh it has generated a bunch of vulnerable Azure methods in the past but it's probably not doing it anymore. So all of this kind of amounts to I don't know what. Um right depending on how we are for time. How are we for time? Am I I'm good. Okay. Then I'll do one more demo here at the end. Uh now I've gone and picked another really obscure method so I don't do anything bad here live. Uh there's a method named Microsoft Azure Management Storage blob container operation extensions get
immutability policy async. So if you're using that in your codebase, watch out. Uh here's the documentation from Microsoft. Uh this takes this parameter, you can't see at the back, but it takes a parameter named if match. And if match is vulnerable to CRLF injection. Uh so I prepared this demo yesterday evening at about 11 p.m. Uh so we'll see how understandable this actually is. I have opened burp here and put the font size to 24 so that you can read the requests. Hopefully that request wasn't interesting. Um I realized I didn't actually show you the code. So here is what we are doing. Uh I went to chatgpt and I said make me some example code
which uses this super long method. It made me some code and I changed it around so that I have a command line application which takes one argument uh and this argument it puts into the if match value of this call to get immutability policy async. Uh so that's all we've got. So let's see we've got this get immutability policy async.exe on the right hand side. I'm going to pass it a value of hello bides. It's going to crash because it's a live demo. Let's find out. No, it didn't. Okay, cool. Uh let's go. I'm sending this through a proxy because I didn't have time to think of a better way to view the request. So on the left hand side
here you can see the request it's making to this beautiful endpoint in Azure. And here we can see the if match header has my value hello besides. Okay, you all know what's going to happen. Let's try to inject a header. Uh side note to put CRLF characters into PowerShell you have to do that funny back slash R. No, not backslash back tick r thingy. I hadn't seen that before. try to Google it. Um, let's see what request we made. We made the if match header with hello b size and we have an injected header of whoop. Uh, all right. We'll do the third one. Let's see if we get to smuggler request. Now, this is going to look weird in my
proxy here because it's all going through the same connection. But we have a first request which is properly terminated and we have a second smuggled request. I scrolled just far enough down that I haven't leaked my whole barrier token, but have showed you that the authorization header ends up in the second request, which potentially makes this pretty nice actually because I can go and interact with any Azure resource I want and this code is going to give me the proper authorization headers for that. Uh, now this is running client side. So, this is the dumb vulnerability I spoke about initially. The idea here is imagine someone had this code in that server, not me on my machine. Uh, all
right. Do we have anything more? We have some conclusions. Excellent. Okay, starting this project, I was hoping that what I would find is a bunch of like vulnerable, I don't know, uh, reverse proxies or load balancers or whatever where I can just like show you nicely in a web view like, hey, I go to this page and this endpoint is vulnerable to CRF injection and it exists in the wild. What I found in reality was some library that uses some library that uses some library that uses a vulnerable method and it's kind of all my examples are my own code, which is a bit sad, but I mean it's still real vulnerabilities obviously. Um in fact
that's a CV so it's very much real. Uh the main thing to learn here is just be very careful with user controllable input. Um this you already knew if you are here. Uh but in the case of for example rest sharp uh like I was saying initially if I'm calling triad without validation I'm not very surprised when there's no validation. But when I'm calling rests add header method and there's nothing in the documentation about any CRLFS or security or whatever it doesn't necessarily occur to me that I need to be extra careful. Um, and if you put this like a couple layers out, like you have a library which uses that again, a library which uses that again,
then it's beginning to be really not obvious that this would be vulnerable. Uh, so just always be extra careful even if you like especially if you don't know what the library is doing. Uh, we got a CV so that's cool and that's fixed. We got a fix in refit which may or may not be released. Uh, who knows about Azure? Uh, probably should actually be looking at this author and Azure Rest API specs uh, repositories. We'll see if I ever have the energy to do that. Uh, and that's it. Thank you very much. [Applause] >> Thank you. Do we have any questions for Sophia? Why couldn't you save the O day for us? Maybe next year.
>> Just kidding. We support responsible. >> Maybe get immutability policy async gets gets TP. Any questions? No. Uh, what led you down this uh to focus on this area? When I >> um at binary security, we have a markdown document called research.md. Someone had pasted in that document. Check out try add without validation. It's vulnerable to CRF injection. And uh I ran with it. >> Fair enough. I kind of had the impression that uh HTTP response injection stuff was like I remember hearing about that a long time ago and I was like that's old school stuff. Now we have to worry about V8 uh type confusion and map confusion. But it seems like even though we get the new
vulnerabilities, the old ones are still >> still kind of there. >> Oh yes. >> Well, thank you very much. Are you here for the rest of the event? Fantastic. Thank you so much, Sophia. Let's uh have a big round of applause.