Forum Discussion
Request for providing help on setting up an iRule
Hi All,
Can you please let me know how can I accomplish the below requirement with an iRule.
Any requests that use any method and have "cs.exe" or "llisapi.dll" in the URI and also have a query string or form post variable called "fInArgs" that contains the string "%3D%23" should return 403 Forbidden.
Thanks,
Abhinay
abhinay please share how you test in postman.
I've tried and it works if the POST body is raw type and looks like this : fInArgs=%3D%23
This is what rules I am using:when HTTP_REQUEST {
if { ([class match [HTTP::uri] contains example_uri_1]) and ( [HTTP::query] contains "%3D%23") }{
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
log local0. "deny URI: [HTTP::uri] query:[HTTP::query]"
}
if {[HTTP::method] eq "POST"}{
# Trigger collection for up to 1MB of data
if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 1048576
}
# Check if $content_length is not set to 0
if { $content_length > 0} {
HTTP::collect $content_length
}
}
}
when HTTP_REQUEST_DATA {
if { [HTTP::method] equals "POST" }{
# Extract the entire HTTP request body and escape it to become a HTTP::uri string (for easier parsings)
set http_request_body "?[HTTP::payload]"
log local0. "http payload: $http_request_body"
# Try to parse type value from the HTTP request body.
if { [URI::query $http_request_body fInArgs] equals "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
} }
}if you use application/x-www-form-urlencoded you will have to match this "%253D%2523"
if { [URI::query $http_request_body fInArgs] equals "%253D%2523" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}or use URI::decode :
if { [URI::decode [URI::query $http_request_body fInArgs]] equals "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}and if it is a form-data:
set varB [findstr [HTTP::payload] "fInArgs"]
if { $varB contains "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}I noticed from other comments in this thread that variable name is fInArgs with an uppercase "i".
Variable name in my code has a lowercase "L" -- I must have read that wrong before. If you just copy/pasted and didn't fix it, it might not match because of this.
Otherwise, I'd expect it to work -- it does in my lab.
Here is an example:
ltm data-group internal example_uri_1 {
records {
cs.exe { }
llisapi.dll { }
}
type string
}when HTTP_REQUEST {
if { ([matchclass [string tolower [HTTP::uri]] contains example_uri_1]) and ([string tolower [HTTP::query]] contains "%3D%23") }{
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}
}For the form post variable, I think you need to have APM.
- NetOpsCommercialNimbostratus
Thanks for your response mihaic.
I see that you have created a data-group for URIs and calling it in the HTTP_Request along with the HTTP Query string which contains "%3D%23".
Can you please let me know how to use this post variable called "fInArgs" in which I can check the string "%3D%23"
Hi abhinay ,
As mihaic figured out his iRule , it should meet your requirements.
I want to add only this part to specify the ( Query string name and value ) in Requests
you can add to mihaic iRule :[URI::query [HTTP::uri] "fInArgs"] equals "%3D%23"] #add this part after and operator in iRule instead of ([string tolower[HTTP::query]...) it is only to be more specified
I think NetOpsCommercial asks for this part , is not it.
mihaic , Did you simulated this irule and get its results ?can you provide what HTTP payload looks like?
As far as I understand you need to look for some variable and its value in the HTTP payload.
Mohamed_Ahmed_Kansoh is right, we need to remove "string tolower" part.
I only tested that the syntax is ok. The functionality, no. Did not have time yet.
Here is the irule with the variable also:(not functional tested):
ltm data-group internal example_uri_1 {
records {
cs.exe { }
llisapi.dll { }
}
type string
}
when HTTP_REQUEST {
if { ([matchclass [string tolower [HTTP::uri]] contains example_uri_1]) and ( [HTTP::query] contains "%3D%23") }{
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}
}
when HTTP_REQUEST_DATA {
if { [HTTP::method] equals "POST" }{
# Extract the entire HTTP request body and escape it to become a HTTP::uri string (for easier parsings)
set http_request_body "?[HTTP::payload [HTTP::header value "Content-Length"]]"
# Try to parse type value from the HTTP request body.
if { [URI::decode [URI::query $request_body fInArgs]] equals "%3D%23" } {
log local0. "fInArgs : $fInArgs"
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}
}
}- abhinayNimbostratus
mihaic, URI along with query that contains "%3D%23" combination is working but the below payload with the body that contains %3D%23 doesnt seem to work. As we are decoding the query I tried "=#" too but no luck.
Any suggestions would be appreaciatedwhen HTTP_REQUEST_DATA {
if { [HTTP::method] equals "POST" }{
# Extract the entire HTTP request body and escape it to become a HTTP::uri string (for easier parsings)
set http_request_body "?[HTTP::payload [HTTP::header value "Content-Length"]]"
# Try to parse type value from the HTTP request body.
if { [URI::decode [URI::query $request_body fInArgs]] equals "%3D%23" } {
log local0. "fInArgs : $fInArgs"
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}
}
}I'm noticing this code is missing an HTTP::collect statement, so HTTP_REQUEST_DATA event will never be fired.
abhinay Have you checked my other response yet?
Hello abhinay ,
I've recently implemented a similar check on one of my customers. Try the following:when HTTP_REQUEST { if { [HTTP::uri] contains "cs.exe" || [HTTP::uri] contains "llisapi.dll" }{ if { [URI::decode [HTTP::query]] contains "flnArgs" }{ set value [findstr [URI::decode [HTTP::query] "flnArgs" 7 &] if { $value contains "#=" }{ log local0. "violation detected: flnArgs=$value" HTTP::respond 403 content "Forbidden" } else { # if URI does not contain parameter, I capture traffic (up to 1MB) and perform this check again on full payload if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } if { $content_length > 0} { HTTP::collect $content_length ; set checkpayload 1 } } } } when HTTP_REQUEST_DATA { if { $checkpayload }{ set cleanpl [URI::decode [HTTP::payload]] set value [findstr $cleanpl "flnArgs" 7 &] if { $value contains "#=" }{ log local0. "violation detected: flnArgs=$value" HTTP::respond 403 content "Forbidden" } } }
Notice that I'm decoding URI so %3D%23 will be normalized to #= , this match is more effective IMO
- abhinayNimbostratus
Oops, you're right - I've lost a couple parenthesis in the copy/paste, also #= should be inverted to =#
Sorry! Fixed below.when HTTP_REQUEST { if { [HTTP::uri] contains "cs.exe" || [HTTP::uri] contains "llisapi.dll" }{ if { [URI::decode [HTTP::query]] contains "flnArgs" }{ set value [findstr [URI::decode [HTTP::query]] "flnArgs" 7 &] if { $value contains "=#" }{ log local0. "violation detected: flnArgs=$value" HTTP::respond 403 content "Forbidden" } } else { # if URI does not contain parameter, I capture traffic (up to 1MB) and perform this check again on full payload if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } if { $content_length > 0} { HTTP::collect $content_length ; set checkpayload 1 } } } } when HTTP_REQUEST_DATA { if { $checkpayload }{ set cleanpl [URI::decode [HTTP::payload]] set value [findstr $cleanpl "flnArgs" 7 &] if { $value contains "=#" }{ log local0. "violation detected: flnArgs=$value" HTTP::respond 403 content "Forbidden" } } }
seems to work in my lab
Dec 21 20:14:52 bigip info tmm6[11336]: Rule /Common/iRule_DC <HTTP_REQUEST>: violation detected: flnArgs===# Dec 21 20:14:55 bigip info tmm[11336]: Rule /Common/iRule_DC <HTTP_REQUEST_DATA>: violation detected: flnArgs===#
abhinay please share how you test in postman.
I've tried and it works if the POST body is raw type and looks like this : fInArgs=%3D%23
This is what rules I am using:when HTTP_REQUEST {
if { ([class match [HTTP::uri] contains example_uri_1]) and ( [HTTP::query] contains "%3D%23") }{
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
log local0. "deny URI: [HTTP::uri] query:[HTTP::query]"
}
if {[HTTP::method] eq "POST"}{
# Trigger collection for up to 1MB of data
if {[HTTP::header "Content-Length"] ne "" && [HTTP::header "Content-Length"] <= 1048576}{
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 1048576
}
# Check if $content_length is not set to 0
if { $content_length > 0} {
HTTP::collect $content_length
}
}
}
when HTTP_REQUEST_DATA {
if { [HTTP::method] equals "POST" }{
# Extract the entire HTTP request body and escape it to become a HTTP::uri string (for easier parsings)
set http_request_body "?[HTTP::payload]"
log local0. "http payload: $http_request_body"
# Try to parse type value from the HTTP request body.
if { [URI::query $http_request_body fInArgs] equals "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
} }
}if you use application/x-www-form-urlencoded you will have to match this "%253D%2523"
if { [URI::query $http_request_body fInArgs] equals "%253D%2523" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}or use URI::decode :
if { [URI::decode [URI::query $http_request_body fInArgs]] equals "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}and if it is a form-data:
set varB [findstr [HTTP::payload] "fInArgs"]
if { $varB contains "%3D%23" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}- abhinayNimbostratus
mihaic, small change in URI from "cs.exe" to "/cs". I dont mind having two different iRules for GET and POST.
Below GET is working abosultely fine
ltm data-group internal uri_list {
records {
/cs { }
llisapi.dll { }
}
type string
}when HTTP_REQUEST {
if { ([matchclass [string tolower [HTTP::uri]] contains uri_list]) and ( [HTTP::query] contains "%3D%23") }{
HTTP::respond 403 content "Forbidden" "Content-Type" "text/html"}
}For POST, I have verified internally and got the postman and see that the key is "_fInArgs=" and it should contain "=#". I have modified your iRule with these values but still fails.
The Postman body is below. Please let me know if anything else is needed.
"body": { "mode": "urlencoded", "urlencoded": [ { "key": "_ApiName", "value": "foo", "type": "default" }, { "key": "_fInArgs=", "value": "A<1,?,'_ApiName'='SessionFree','_ConnectionName'=#AAAA>", "type": "default" } ] },
from what you shared the the key is "_fInArgs= " and the value is not what you asked for . it is not "%3D%23"
"key": "_fInArgs=", "value": "A<1,?,'_ApiName'='SessionFree','_ConnectionName'=#AAAA>",
the format you shared seems to be a JSON
try to put something from the value.
- abhinayNimbostratus
mihaic Thats right Sorry for the confusion, an Internal team was testing this earlier. I got the Postman file from them and checked that the key and value were different.
I already made changes and tested for body with "_fInArgs=" that contains "=#" which did not work tried "_fInArgs=" that contains "SessionFree" which did not work either. your help will be appreciated.
when HTTP_REQUEST_DATA {
if { [HTTP::method] equals "POST" }{
# Extract the entire HTTP request body and escape it to become a HTTP::uri string (for easier parsings)
set http_request_body "?[HTTP::payload [HTTP::header value "Content-Length"]]"
# Try to parse type value from the HTTP request body.
if { [URI::decode [URI::query $request_body _fInArgs=]] contains "=#" } {
log local0. "_fInArgs= : $_fInArgs="
HTTP::respond 403 content "Forbidden" "Content-Type" "text/html"
}
}
}
for it works this:
set token [lindex [ regexp -inline -- {"value": "(.+)"} [HTTP::payload] ] 1]
if { $token contains "SessionFree" } {
log local0. "token: $token"
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
} }But the problem is that it checkes everything starting teh first "value" it finds till the end.
I could not yet do a search only for key "_fInArgs=" and match only something in its value.
As this is a json format, we need a way to parse json.
here is a better way.
set varB [findstr [HTTP::payload] "fInArgs=" 33 type]
if { $varB contains "SessionFree" } {
HTTP::respond 403 content "You don't have authorization to view this page. Access Denied" noserver Content-Type text/html Connection Close Cache-Control no-cache
}I've managed to extract the value field.
This works for me.
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com