
http parameter pollution it is a security bug that can easily go unnoticed in today's microservices architecture this type of park can be more prevalent my name is pedram hayati i am a security instructor at a security education company called secting from sydney australia in today's talk i will be going through what http parameter pollution is how we can identify it and more importantly how we can effectively address this bug in our programs let me start by giving you a little bit of background information query in uniform resource identifier or commonly known as uri is a series of field value pairs some characters are reserved and have a special meaning things such as question mark equal sign
or ampersand for example question mark is a start of the query parameters ampersand will separate out different fields now by having that in mind what is the value of action in this given url is the value transfer or is it withdrawal or none of them or all of them well the answer is it depends it depends on the technology stack that we are using for our programs and i have example of them in this table php with apache server in the front will interpret the first occurrence of action field java using a spring framework on the other hand will return the last value of action and in javascript we will receive an array containing both
both values and this is the same story when we talking about python ruby golang and many other frameworks what is the problem the problem lies in the well rfc itself which does not mandate how to interpret multiple query parameters with the same field name now apart from obviously some functionality type bugs what security problems can we face well as you could imagine depending on the program or the middleware that we are using these different interpretation can result into authentication bypass authorization bypass and quite commonly validation bypasses and can you can imagine in today's microservices architecture we may have different technologies and by them different programs written in by different programming languages as are in different programming languages
and they may interpret different parts of the input and they send that across and this can result into obviously some functionality but more importantly some security issues let's look at one real world example or incident of this issue which goes back quite quite a lot to the time where we had a thing called open source with application firewalls well firewall was a buzzword back in the days to something that we can put in our networks to protect our programs open source of application firewall or mod security was a popular web application firewall that was looking at the traffic that was coming inside the program and goes out of our programs and was checking that traffic most
commonly http traffic for common blacklisted patterns within much security there was a rule set and i should say mod security is also still available today there was a rule set that was checking if this incoming traffic is may have some suspicious payloads inside and if it will mark or stop that traffic before that request will reach our program and similarly much sick was also could be set up to look at the response traffic and by looking at for example if the response traffic contain some stack information some detailed errors might say we'll block those traffic as well supposedly if the attacker we have a program which is vulnerable to sql injection an attacker wants to enter a payload
to receive or dump all day user table so in example you can see here attacker wants to enter select username and password from users table obviously mozick will stop these type of patterns because it's a clear example of sql injection now if the same attack will break down the payload into multiple fields all with the same name and here in the example i in the slides is the field is page we have that payload broken down in multiple payloads all with the same name but with the different values it turned out to be that modseg will only looking at the first occurrence of the page parameter or the field that is being recurring in the query parameters
and will happily allow that to go in because that field did not contain any suspicious pattern however the program which is vulnerable to sql injection may interpret that differently concatenate all those fields value together and here we go attacker was managed to bypass this work or bypass this validation better sense so why we have this problem well the problem goes back to the way that the programs are interpreting these situations or http parameter pollution in other sense that when a request parameter with the same field name is interpreted differently the root cause behind this type of attack is is that we typically in our microservices architecture or any type of programs we may have a
component a or a type a component or a gateway type component that sits in in front of our program and typically does validation or verify for something an example i have here if we our program receiver an environment receive a get request we to value bar and bus for the same field foe the component a will perform the validation and depending on the technologies that used to develop that program bad or bad or bad and bass may get validated and then later on this component will send this value down to other microservices or inner functionalities in our program and again depending on the classes depending on methods or libraries that we are using different values will be
interpreted let's now start talking about how we can detect http parameter pollution in our programs i will talk about two common ways that you can go and find this bug one through runtime analysis or black black box type assessment and then later i will talk about how you can find this bug when you do a static code analysis or you do white box type assessment this bug is relatively easy to detect during runtime analysis we can simply just duplicate the parameters in the query string and see how the program will respond or which one of these fields was interpreted by the program now the interesting part is that you can do the same thing read things like post requests
you can look at the post body and duplicate those parameters that you see within the post body now more interestingly you can do the same thing with the http request headers there are some important request headers such as authorization header which typically contains authentication tokens commonly jw3 or cookie headers with again which have have some sensitive values see if you duplicate these headers rather than sending one authorization header supplied their program with multiple authorization headers one with a valid say authentication token the other one with invalid signature but a valid user id and c you may be able to get access to someone else's account by duplicating the authorization header because you may find that the program
environment is set up that the validation is done by a different service and that service may only look at the first occurrence of the authorization header but not the second one and similarly we can do the same thing with cookie when it comes to the static analysis you can look at those parameters that obviously coming from an untrusted source and you look at if this parameter being passed around in the environment or being passed around to the other services and more importantly look at if the value or the if the original parameter being passed around or the interpreted value if the original value is being passed around there is a high likely that http parameter pollution
can happen now i would like to stop talking and talk about the demo and go through all these things that we just talked about and to see in action what http parameter is how we can detect it and later on talking about how we can prevent it the demo program as you can see you can find it on lab gitlab.com js http parameter pollution and i will go through that with you now this is our demo program let me talk a little bit about the structure of this demo so it's a broken javascript what i mean by broken javascript program is a program that is vulnerable to http parameter pollution and to run this program you can just
simply clone first this repository after you forking it and uh just run make build this will build the the program install all the libraries and dependencies and then once you run make run it will run the program and we will go through the rest of it later the program has two main directories uh you can find the program itself within the source directory if you look at the app.js that's the main logic of the code and you can we can see here it expect a get request on root and within there it will look at two query parameters one call action the other one called amount and then later on we'll pass this to a component or sorry the
method called payment which does some action on these two all right on line 24 we can see that the program expect to receive value transfer within the query parameter action i will not go through the details of the code at this stage the other thing for us is interesting to know is the test directory which contains two types of tests uh app.test.js contained the typical usability test app security.test.js are example of some security unit test at this stage we are not going to look at the details of it so okay now let's look at our program and i have already cloned this the program here i've already done make build let's just run it again he's
already run build and set up all the dependencies i will run this program now now as we can see the server is listening on port 8080 let me start sending a request to our program it runs in localhost on port 8080 then i will give it a an action parameter with the value well transfer as we could see in the code following with amount field we'd say a value 100 and let's see how the program will respond as we can see it successfully transferred 100 now what will happen if i change this transfer for example to something different let's put it let's do something different called withdraw as we can see the program responded that
you can only transfer an amount so this program is expected to only receive a transfer action and there is a validation within the code that does that now if you remember we talked about parameter http when we were talking about http parameter pollution we talked about duplicating these query parameters let's see what will happen if i duplicate the action parameter let me change it to the original transfer and now i want to enter another action field with a different value this time but i cannot simply send this this will not run because due to the way that you know my my shell script is my shell environment is set up i need to do a little bit of
change here the first thing is that i need to find the url encoded value of the ampersand to do that you can just look at the ascii man page sorry i didn't split properly and i can look at the ampersand here and i can see it's equals to 26 in higgs so going back i can enter a url encoded or percentage encoded value of that and that is equivalent of ampersand and let's see what will happen here well successfully withdraw a hundred dollars so this is just to show us that yes the program is interpreting the second value now when we are giving a duplicate action field now is the time we go back to our source code
and see what actually happens so if i look at the source the app.js right on line 24 there is a check that is being done to see if this action parameter includes the value transfer okay that's that's firstly you may say that okay this is a quite a weak check because it will look at inside any part of the query parameter to find transfer and in this case because transfer was there and also with the row because transfer will this if condition is true then it will go to the second line which sorry the line 25 which will pass the value that original value which i was talking about not the interpreted value the original untrusted
value to this other method let's look at the content content of this method which is inside the file called payment.js and supposedly this could be a you know another service uh or another inner program between our in within our setup and it's expected to do both withdraw and an action so these are just some dummy code i've put here so if it checks if the action contains the you know the word withdraw it will does the withdraw for us it's kind of like a fake withdrawal or if the action contains the word transfer it will does the transfer for us now the way that this program is set up is that the payment does not care what
action the user want this is the job of the the app after js the main program to perform the validation and only allow in the authorized actions so now i guess you already got an idea that what is the problem and what where the issue is now let's talk about how we can address this issue like can i just go back can i do something here that effectively address this part let me let me talk talk about that a little bit later but for now let's go back to our slides and uh talk a little bit about how we can prevent this sort of bug i commonly see like as a security professional we do
not really talk in lens how the programmers need to go and fix these sparks properly or in the majority of the cases i've seen that you know there is a link given to an online resource and we expect our programmers to go there and figure out what is the best way to fix this bug but unfortunately over these many years that i was in this field i could see that this has resulted into even more bugs because in in most cases these uh generic type recommendations are incomplete and may contain loads of information that is not even relevant to our to our developers and a lot of times what will happen is we will see that these type of vlogs are
just address using type like a band aid type type approach or just symptom type approach they just go there and let's let's let's let's just again look at the example let me just go there and they just put let's just mark this issue come in this issue and maybe may just add a more stronger check right here so request.query that action triple call transfer well you may agree with me that this will address this issue however this is not addressing the root cause of the problem the main problem of this program which is inherently secure so tomorrow if someone comes and adds another endpoint here or introduce a new controller they need to also make sure that all
these checks or security checks are there and as the programs become more complex as the programs are starting to interacting with different different services you can see commonly these checks are either being is skipped or in other another sense it just makes the program ugly it makes the the readability of the program quite hard to to handle so i was over and over thinking could it be an approach or could it be a different way of thinking here that we it can guide the programmers with a with an approach that it will never result to problem like this in the first place so can we think about a way that we program or a guide or a principle that
it will not even result a situation like this that later on we need to to put a patch on it well it turned out to be yes there is a way we can we can do and uh there's a programming approach known as defensive programming that has been around to build robust safety critical application and interestingly secure programming is also a subset of defensive programming the the promise of defensive programming is that it guides us this approach that plans for contingencies or unforeseen errors or in our case runtime exceptions where security is a runtime exception it tries to plans for them in the design and implementation stage of the program and in fact the concept of
defensive programming or defensive design has been around in other and industries for very long time for example if you live in australia or new zealand or some pacific islands this is what you see on the wall this is a power wall socket and depending on the amps there is a different design of this socket the this design or this defensive design enforces the user like me only plug an appliance with equal or lesser current rating to the to these plugs which obviously if we didn't have this defensive design a user may connect an appliance let's say with 25 amp to a volt socket which only gives out 10 amp and that could result in two well
short circuit circuit or fire so defensive design was inherited was inside this the the way that these guys they've designed the wall socket now when it comes to defensive programming my work recently has been expanding on the security aspect of the defensive programming and rather than focusing on vulnerabilities over top tens or all those sort of common type bugs and then going to the programs try to patch them i was trying to collect and come up with uh different design patterns and principles that can guide the programmers to write the program secure from the get go at the same time handle the complexity of a number of security bugs by following a principle this is
something we haven't even discussed in this in this in this talk but some of the bugs are not that easy to patch just due to the nature of it at the same time the other thing is how we can bring in all those runtime exceptions earlier in the development phase of our program so we can plan for it we can we can think about it and fix it at that stage and interestingly some of these design patterns or principles can implicitly address many other classes of security bugs i have divided these principles to you know different categories of core and supporting and i'm not planning to go through them in this talk this is itself in another
talk but for the sake of the demo examples that i have i will go through a few of these principles just to see how we can address a bug similar to the http parameter pollution and you will you may also agree with me that some of these principles not just addressing the bot but even if someone didn't know about http parameter pollution they could address this this issue the first principle untrusted data validation this is commonly known as input validation and you know there is technically it will address the block however when we are dealing with a complex program an enterprise type program it is not enough and this is like the promise of the
other principle to make sure this uh program is robust in those situations so untrusted data validation is simply about making sure when the data sorry the data must be validated as it crosses the boundary between untrusted and trusted environment now if we look at our program here let me just shift here within the demo we have another branch called patch which there is a sample sorry check out patch there is a you can find a sample patch for this issue the first thing is within the patch program you know we haven't touched our the the test so the tests remain remain the same was after test security.test but within the source directory i have made some changes right here
the first thing let's just look at the app.js to see how a patch example gonna look like the first thing you can notice here is uh we are defining two constant one is called action the other call amount and it's coming from these two which later i will talk about data types called action and emand and that's it and then later on i will pass these validated values to our payment method for for the rest of the program if you look at the action and amount they are all defined in a separate files uh and i call it types let's look at action as an example so what i've done here is i have defined
a new type in our program and the type is is action now if you think a little bit the way that action was defined in our broken example action was defined as a string and in a lot of programs a string is not a good representation of this concept and this goes back to i don't want to make it more complex this actually goes back to domain driven development where it encourages to model your program as close as possible to the reality of this program or the business context of this program when we define things as generic like a string or integer or number although they can you know they can do the work they can model something from the
reality but it's not as close as possible it's not as strict enough that what we mean by action in the real world so in the context of this program action is is a type that can only contain two values transfer and withdraw and that's it it is not a string it's not intriguing it's not even an enum action is action so by having that by modeling our program in this way by just following the business context or better to say the domain rules we can enforce these checks without even thinking about the the security problems or security things that may arise so in this example the first thing i will check is well obviously if my value is a string
by default is a string and the other thing i pretty much check that if this value that i have is contains the the value so the field contains the value transfer and that that's pretty much it with the exception of the line 16 which i'm doing this is specific to javascript i'm making sure that this type that i have is immutable with the exception of that you can see all other checks that i'm doing there is nothing related to the security here these are pretty much my domain rules so as a programmer if i was designing this if i just listening to my domain expert about hey what action means in the context of this program
then i could simply apply these two checks and surprise this will also address implicitly the problem with the http parameter pollution in this example let's also look at our amount data type it's similar to the previous one however again in weekly type and also dynamically type languages one of the first things we need to do we need to convert or the the value to the type that we expect and this is what i've done on line five and specific to the javascript we also need to immediately check that if this value this number value that we have is not a number or not i'm not going through the detail of why i did use this
number that is not not just is that itself but this is just making sure these first few lines that okay what i'm receiving is a number type and then i will apply my domain rule which is saying in our case okay i'm expecting to receive an amount or my program should process an amount which is between one and i guess 10 million and that's it and obviously this last line is just making sure my type is immutable across my program it just makes it beautiful and it stops unexpected changes within our code so having these two let's also look at our payment service or payment method as you can see i have not changed anything here
because the e this issue is not it should not be even addressed at this stage if we are expecting the our gateway program or the action is the place that all the validation should happen payment should just be as it is maybe it's a different team in the company is actually working on it and may expect you know receiving values like withdrawal from another components from another service so we are not going to go there and fix it although you the the first no gut feeling will be oh let's just go and fix payment but in reality in our case once we done these changes to to the our main program uh sorry here let me just quit this and
run the tests again and see what happens so let's just rebuild the program sorry okay and uh one thing that i forgot to mention at the beginning was we have two sets of tests one is our typical usability test the first this test to just check if the program function as expected so in the first well in the second test it will check if there is a request to transfer 100 it should return 200 with a success message and if there is a request to withdraw 100 dollar the program should return 400 with an error message now to run this test we can simply just run make test and it's already done the test nothing failed here the other sets of
tests are our security tests and in this example this security says effectively does exactly what we did during the runtime analysis it its request to transfer and we draw a hundred dollar and expect to that program handles this with 100 with 400 error and as you can see here we are we are passing a query parameter action with the value transfer percentage 26 which is a url encoded for the value ampersand following with row so let's run security test let me clean the program again and hopefully this will show our test will rely on again just running the cached version at the moment all right so make test let it run for a while
okay the dependencies are set up the source copying the tests and running our test using and we can see that test is passed with no issue and similarly security test and hopefully the program yes gonna pass let's just you know test it together as well so again i got the program and let's just send the same command that we did previously and let's see what the program gonna respond obviously i didn't run it so let's run the program
and uh uh let's just see what happened i make build obviously and copying the build image and then run perfect we got that running and here let's run the calculator yes on our program and nicely handle the http parameter pollution that was that pretty much that i wanted to talk about i hope well i cannot cap and answer your questions in this recording but hopefully by the time this recording will be played i will be there to answer your questions i hope this was useful the the intention of this talk was not so much talking about another vulnerability or another bad thing that can happen and get exploited but more around how even some widely known type
bugs are not that trivial to address or in our complex program or complex environment these bugs even are even harder to to address the thing about this program that i have here if you see when i define new types these types can be easily shared around with your with your other services within within your environment so everyone can make sure all those services can make sure that they are applying the consistent validation on on these uh these parameters that you're dealing with one thing i want you to leave with is that this idea of defining custom types was also nicely captured in a book called secure by design and there are the authors are talking about
domain primitive which is effectively similar to what we just did we define a custom type or in another in a domain driven development sense we defined a value object and finally here are some references and if you want to find me or contact me these are my details if you're part of sick talks you can definitely find me on sicktalks.slack.com and that was it thank you very much and see you later