ModSecurity
ModSecurity copied to clipboard
IIS multiple response headers with the same name
I am using IIS Application Request Routing (ARR) with ModSecurity. ModSecurity is installed and configured with the OWASP Core rule set on Windows 2022. I am trying to improve the rule set by incorporating session based logic.
I am using this rule to extract the session cookie:
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "(?i:(wordpresspass_.*?|j?sessionid|(php)?sessid|(asp|jserv|jw)?session[-_]?(id)?|cf(id|token)|sid)=([^\s]+)\;\s?)" \
"chain,phase:5,id:'981062',t:none,pass,nolog,capture, \
setsid:%{TX.6}, \
setvar:session.sessionid=%{TX.6}, \
setvar:session.valid=1, \
expirevar:session.valid=3600, \
setvar:session.country_name=%{geo.country_name}"
SecRule UNIQUE_ID "(.*)" "chain,t:none,t:sha1,t:hexEncode,capture, \
setvar:session.csrf_token=%{TX.1}"
SecRule REMOTE_ADDR "^(\d{1,3}\.\d{1,3}\.\d{1,3}\.)" "chain,capture,setvar:session.ip_block=%{tx.1}"
SecRule REQUEST_HEADERS:User-Agent ".*" "t:none,t:sha1,t:hexEncode,setvar:session.ua=%{matched_var}"
The problem is, only the last Set-Cookie set by the application is found. I wrote a rule to help me determine how many Set-Cookie headers ModSecurity thinks I have by :
SecRule &RESPONSE_HEADERS:/Set-Cookie/ "@gt 1" "chain,phase:5,id:'981062',t:none,pass,nolog"
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "((?s).*)" \
"t:none,nolog,capture, \
setsid:%{TX.1}, \
setvar:session.sessionid=%{TX.1}, \
setvar:session.valid=1"
When greater than 1 (“@gt 1”) is set, the session file never gets created, but if it “@gt 0” the last Set-Cookie header is saved.
This https://coreruleset.org/20230717/cve-2023-38199-multiple-content-type-headers/ States:
“This issue was initially reported to the CRS project on 24 March 2023 via the ModSecurity project. We quickly established that the CRS reference platform was not affected (ModSecurity 2.9.x on Apache 2.4). This is because the Apache web server merges identically titled header fields into one, separating any different values with commas (as described in the HTTP standard). The problem is that the situation is different on other platforms. While Apache (our reference platform) merges Content-Type headers together allowing this behavior to be detected, Nginx, for example, will retain each separate, identically named header: no merging occurs.”
This states: https://learn.microsoft.com/en-us/answers/questions/555576/setting-multiple-response-headers-with-same-name-d “IIS doesn't allow custom response headers with the same name.”
Chrome at the end user, does show all 4 Set-Cookie headers in Developer Tools.
What IIS, ARR and/or ModSecurity configuration setting will allow ModSecurity to see all Set-Cookie headers?
Hello @Rtw915 ,
As part of your description, you raise CVE-2023-38199. I don't believe that is relevant to your situation. The use case there is that multiple Content-Type request headers were, in fact, received by ModSecurity, and that the ambiguity could result in the wrong choice for body parsing.
In your case, you appear to be describing a situation where you believe you are sending multiple response headers but that ModSecurity only sees one.
Things you could check to make sure you are fully understanding your situation:
- does the client only receive one Set-Cookie header?
- does the value of that single response header correspond to only one header (e.g. multiple header values have not been combined into a single value that is a comma-separated list)
My guess is that your issue has nothing to do with ModSecurity, and that you are in fact only sending one Set-Cookie response header. While IIS does seem to enforce some restrictions on duplicate response header names, I would be surprised if there is no way to work around this (for Set-Cookie at least), A quick search found this:https://stackoverflow.com/questions/71348499/adding-and-manipulating-multiple-set-cookie-headers-in-iis , which might be useful to you.
Thank you for clarifying the situation with CVE-2023-38199.
The client gets all four Set-Cookie headers. It looks to me each one is its own and not combined into a single value.
Can you confirm, does the screenshot look like it's only sending one Set-Cookie response or for individual ones?
I enabled the Failed Request Tracing role and configured it fallowing this guide https://learn.microsoft.com/en-us/troubleshoot/developer/webapps/iis/health-diagnostic-performance/troubleshoot-arr-using-frt-rules .
Failed Request Tracing screenshot:
I think this means IIS is seeing the headers correctly. Is my understanding correct?
In an attempt to rule out regex issues I made this test rule:
SecRule RESPONSE_HEADERS:/Set-Cookie/ "((?s).*)" \
"phase:5,id:'981062',t:none,pass,nolog,capture, \
setsid:%{TX.1}, \
setvar:session.sessionid=%{TX.1}, \
setvar:session.valid=1, \
expirevar:session.valid=3600"
This is what the session file contains:
I expected to see all four Set-Cookie headers, but I only see the last one. Just to be clear, I'm trying to capture ASP.NET_SessionId value.
How can I further troubleshoot ?
Hi @Rtw915 ,
Usually the simplest way to view which response headers ModSecurity sees is to examine part F of the audit log.
A good way to better understand what is happening is to use ModSecurity's debug log (particularly at level 9). The log will provide information about the processing that has occurred for each rule that is executed.
Regarding your most recent 'test rule': Perhaps I've misunderstood you somehow, but you expect the actions of the rule to execute against the content of each of the four header values, right? In that case, note that the 2nd, and subsequent executions are overwriting the previous values. I.e for the active 'session' there is a single 'sessionid' -- and you are replacing the value every time you execute 'setvar'.
Hello @martinhsv,
Thank you for your help!
I enabled audit logging and was able to find the initial response.
- I don't understand why the source port in part A is 80. A source port of 80 seems wrong since it should be an empirical port.
- The IP behind the obfuscated source address is my home's public IP (where I'm testing from).
- Also, everything should be HTTPS, so why is the destination port 80?
- In Part F I don't understand how ModSecurity is getting "HTTP/1.1 500 Internal Server Error," when from a client perspective everything seems to be working.
- Lastly, there is only 1 Set-Cookie, so that explains that, but why?
I set the debug log at 9 like you suggested and was able to review. Honestly, I'm having a hard time understanding where to look. I was able to find the rule and this repeats 6 times throughout the log.
[11/Oct/2023:18:03:09.115187 --0400] [ATLPRDDMZARR071/sid#1de51866140][rid#1de52b9e6b0][/][4] Recipe: Invoking rule 1de51aea248; [file "C:\Program Files\ModSecurity IIS\owasp-modsecurity-crs/rules/modsecurity_crs_15_customrules.conf"] [line "56"] [id "981062"].
[11/Oct/2023:18:03:09.115187 --0400] [ATLPRDDMZARR071/sid#1de51866140][rid#1de52b9e6b0][/][5] Rule 1de51aea248: SecRule "RESPONSE_HEADERS:Set-Cookie" "@rx ((?s).*)" "phase:5,auditlog,id:981062,t:none,pass,nolog,capture,setsid:%{TX.1},setvar:session.sessionid=%{TX.1},setvar:session.valid=1,expirevar:session.valid=3600"
[11/Oct/2023:18:03:09.115187 --0400] [ATLPRDDMZARR071/sid#1de51866140][rid#1de52b9e6b0][/][4] Rule returned 0.
[11/Oct/2023:18:03:09.115187 --0400] [ATLPRDDMZARR071/sid#1de51866140][rid#1de52b9e6b0][/][9] No match, not chained -> mode NEXT_RULE.
I'm going to configure a rule like this to help lessen the noise:
SecRule REMOTE_ADDR "@streq 192.168.1.1" \
phase:1,nolog,pass,ctl:debugLogLevel=9
Hi @Rtw915 ,
If you add two Set-Cookie headers in the web page itself (using the technique that I linked to in my first reply), do you still only see one Set-Cookie header in ModSecurity's part F output?
How about if you use that same technique, but for response headers with a response header names that are not in the 'well known header names' category? E.g. if you add two response headers both named 'MyCustomHeaderName'?
Based on recent inspection of the code, my guess is that in the first case you will still only see one Set-Cookie header, but that you might see two 'MyCustomHeaderName' headers.
Hello @martinhsv,
Sorry it took so long, I've been sick for a couple of weeks.
I was able to do as you asked. I added two Set-Cookie headers in the outbound rewrite rules on the origin server and only the second "mycookie2" showed up in ModSecurity's part F output. However, the user browser showed the 4 original cookies and both test cookies.
I then changed "RESPONSE_Set-Cookie" to "RESPONSE_MyCustomHeaderName" and both showed up in the user browser; however, only the second "MyCustomHeaderName" is in ModSecurity's part F output.
We are also stuck still trying to figure out what is causing the 500 logged in part F. The origin server and the ARR proxy server IIS logs and event logs don't show any 500's. Also the user browser dev tools don't show any 500 either.