Forum Discussion

Brad_Anderson's avatar
Brad_Anderson
Icon for Nimbostratus rankNimbostratus
Jan 20, 2022

Creating an iRule from external source using AS3

I am attempting to create a new iRule using AS3 by pointing to an external file and can't seem to get the declaration and/or rule correct. I am receiving the below error when trying as is. I have tried iterations of braces around each when clause and around the entire iRule, but can't seem to get the syntax right.

Anyone have any luck with this? If not, how are you declaring complex iRules within your AS3 declaration without having to manually escape all the json special characters?

Error:

 {"message":"Declaration failed: 01070151:3: Rule [/Common/Shared/log4j_mitigation] error: /Common/Shared/log4j_mitigation:1: error: [braces are required around the expression][when HTTP_REQUEST {\n  # Version 2.0 - 2021-12-11 23:40 Eastern\n  # - Handling nested URI encoding\n  # - Improved matching\n  # Version 1.0 - 2021-12-11 06:10 Eastern\n  # - Initial release\n  # less aggressive regexp for those concerned about false positives \\\"\\\\$\\\\{(\\\\$\\\\{env:[^:]+:-|\\\\$\\\\{[a-z]+:)\\?j\\\\}\\?(\\\\$\\\\{env:[^:]+:-|\\\\$\\\\{[a-z]+:)\\?n.+:.+\\\\}\\\" (remove quotes)\n  # very aggressive regexp \\\"\\\\$\\\\{.+\\?\\\\}\\\" (remove quotes)\n  # URI – based on 200004474\n  set tmpUri [HTTP::uri -normalized]\n  set uri [URI::decode $tmpUri]\n  while { $uri ne $tmpUri } {\n    set tmpUri $uri\n    set uri [URI::decode $tmpUri]\n  }\n  if {[string tolower $uri] matches_regex {\\\\$\\\\{}} {\n    log local0. \\\"log4j_rce_detection drop on URI: $uri\\\"\n    drop\n    event disable all\n    return\n  }\n  set tmpReq [HTTP::request]\n  set req [URI::decode $tmpReq]\n  while { $req ne $tmpReq } {\n    set tmpReq $req\n    set req [URI::de","level":"error"}

iRule:

when HTTP_REQUEST {
  # Version 2.0 - 2021-12-11 23:40 Eastern
  # - Handling nested URI encoding
  # - Improved matching
  # Version 1.0 - 2021-12-11 06:10 Eastern
  # - Initial release
  # less aggressive regexp for those concerned about false positives "\$\{(\$\{env:[^:]+:-|\$\{[a-z]+:)?j\}?(\$\{env:[^:]+:-|\$\{[a-z]+:)?n.+:.+\}" (remove quotes)
  # very aggressive regexp "\$\{.+?\}" (remove quotes)
  # URI – based on 200004474
  set tmpUri [HTTP::uri -normalized]
  set uri [URI::decode $tmpUri]
  while { $uri ne $tmpUri } {
    set tmpUri $uri
    set uri [URI::decode $tmpUri]
  }


  if {[string tolower $uri] matches_regex {\$\{}} {
    log local0. "log4j_rce_detection drop on URI: $uri"
    drop
    event disable all
    return
  }


  set tmpReq [HTTP::request]
  set req [URI::decode $tmpReq]
  while { $req ne $tmpReq } {
    set tmpReq $req
    set req [URI::decode $tmpReq]
  }


  # Header – looks for ${j…} or ${${…}}
  if {[string tolower $req] matches_regex {\$\{\s*(j|\$\{).+?\}}} {
    log local0. "log4j_rce_detection drop on header: $req"
    drop
    event disable all
    return
  }


  # Payload – looks for ${j…} or ${${…}}
  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 {
  set tmpPayload [HTTP::payload]
  set payload [URI::decode $tmpPayload]
  while { $payload ne $tmpPayload } {
    set tmpPayload $payload
    set payload [URI::decode $tmpPayload]
  }


  if {[string tolower $payload] matches_regex {\$\{\s*(j|\$\{).+?\}}} {
    log local0. "log4j_rce_detection drop on payload"
    drop
    event disable all
  }
}

AS3 json:

{
   "class": "AS3",
   "action": "deploy",
   "persist": true,
   "declaration": {
      "class": "ADC",
      "schemaVersion": "3.0.0",
      "id": "molecule_192.168.121.79_1642700459",
      "label": "molecule_192.168.121.79_2022-01-20T17:40:59Z",
      "remark": "DTI f5 as3 declaration for molecule_192.168.121.79",
"Common":{
      "Shared": {
            "class": "Application",
            "log4j_mitigation": {
                  "class": "iRule",
                  "iRule": {
                        "url": {
                              "skipCertificateCheck": true,
                              "url": "https://xxxxxxx/Bradley.Anderson/irules_test/-/raw/main/log4j_mitigation.irule"
                        }
                  }
            },
            "template": "shared"
      },
      "class": "Tenant"
},"Molecule":{
      "Molecule-API": {
            "class": "Application",
            "molecule_api": {
                  "class": "Service_HTTP",
                  "pool": "molecule_api_pool",
                  "virtualAddresses": [
                        "192.168.100.101"
                  ]
            },
            "molecule_api_pool": {
                  "class": "Pool",
                  "members": [
                        {
                              "serverAddresses": [
                                    "10.0.1.5",
                                    "10.0.1.6"
                              ],
                              "servicePort": 80
                        }
                  ],
                  "monitors": [
                        "http"
                  ]
            }
      },
      "Molecule-Web": {
            "class": "Application",
            "molecule_web": {
                  "class": "Service_HTTP",
                  "pool": "molecule_web_pool",
                  "virtualAddresses": [
                        "192.168.100.100"
                  ]
            },
            "molecule_web_pool": {
                  "class": "Pool",
                  "members": [
                        {
                              "serverAddresses": [
                                    "10.0.1.3",
                                    "10.0.1.4"
                              ],
                              "servicePort": 80
                        }
                  ],
                  "monitors": [
                        "http"
                  ]
            }
      },
      "class": "Tenant"
},"Foo":{
      "Foo-Web": {
            "class": "Application",
            "foo_web": {
                  "class": "Service_HTTP",
                  "pool": "foo_web_pool",
                  "virtualAddresses": [
                        "192.168.100.102"
                  ]
            },
            "foo_web_pool": {
                  "class": "Pool",
                  "members": [
                        {
                              "serverAddresses": [
                                    "10.0.1.7",
                                    "10.0.1.8"
                              ],
                              "servicePort": 80
                        }
                  ],
                  "monitors": [
                        "http"
                  ]
            }
      },
      "class": "Tenant"
}}
}