Forum Discussion

doddy's avatar
doddy
Icon for Nimbostratus rankNimbostratus
Jul 27, 2013

Detect HTTP Pipelining Request

Good day all...

 

 

I am currently looking for method to detect HTTP pipelining request. This pipelining is currently exploiting our vulnerability in which cannot detect subsequent request on HTTP request in pipelining form (this may include someterm called HRS/HTTP Request Smuggling).

 

The sample request in text format is as follows

 

GET somehost-A.com:443 HTTP/1.1\r\n

 

Host: somehost-A.com:443\r\n

 

\r\n

 

GET http://somehost-B.com/ HTTP/1.1\r\n

 

Host: somehost-B.com\r\n

 

\r\n

 

 

The request above sent in a single frame, which should be meant a single socket. The "\r\n" delimiter between request seems to be a legitimate method to do the pipelining.

 

From some traces, I found that HTTP_REQUEST event fired for each subrequest.

 

Tried to detect and reject this pipeline request using this iRule

 

when HTTP_REQUEST {

 

-----

 

if {[info exists httpmethodprev]} {

 

log local0. "rejected HTTP pipeline"

 

reject

 

return

 

} else {

 

set httpmethodprev [HTTP::method]

 

}

 

-------

 

}

 

 

But the first request, in which the method saved on httpmethodprev variable, is not rejected.

 

Only the subsequent request successfully being rejected.

 

 

Any help are appreciated.

 

9 Replies

  • as Kevin suggested, when pipelining is disabled, bigip will terminate a connection after responding 1st request.

    e.g.

    [root@ve10:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.252:80
       ip protocol 6
       profiles {
          myhttp {}
          tcp {}
       }
    }
    [root@ve10:Active] config  b pool foo list
    pool foo {
       members 200.200.200.101:80 {}
    }
    [root@ve10:Active] config  b profile myhttp list
    profile http myhttp {
       pipelining disable
    }
    
     client sends http pipelining
    
    [root@centos17 ~] echo -en "HEAD /frist HTTP/1.1\r\nHost: \r\n\r\nHEAD /second HTTP/1.1\r\nHost: \r\n\r\n" | nc 172.28.19.252 80
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:46:47 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
     packet trace
    
    [root@ve10:Active] config  ssldump -Aed -nni 0.0 port 80
    New TCP connection 1: 172.28.20.17(47892) <-> 172.28.19.252(80)
    1374921376.8812 (0.0011)  C>S
    ---------------------------------------------------------------
    HEAD /frist HTTP/1.1
    Host:
    
    HEAD /second HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    1    1374921376.8813 (0.0000)  C>S  TCP FIN
    New TCP connection 2: 200.200.200.10(47892) <-> 200.200.200.101(80)
    1374921376.8842 (0.0029)  C>S
    ---------------------------------------------------------------
    HEAD /frist HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    1374921376.8853 (0.0010)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:46:47 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    1374921376.8853 (0.0040)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:46:47 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    2    1374921376.8853 (0.0000)  C>S  TCP FIN
    1    1374921376.8853 (0.0000)  S>C  TCP FIN
    2    1374921376.8864 (0.0010)  S>C  TCP FIN
    
  • this is when pipelining is enabled (default).

    [root@ve10:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.252:80
       ip protocol 6
       profiles {
          http {}
          tcp {}
       }
    }
    [root@ve10:Active] config  b pool foo list
    pool foo {
       members 200.200.200.101:80 {}
    }
    
     client sends http pipelining
    
    [root@centos17 ~] echo -en "HEAD /frist HTTP/1.1\r\nHost: \r\n\r\nHEAD /second HTTP/1.1\r\nHost: \r\n\r\n" | nc 172.28.19.252 80
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
     packet trace
    
    [root@ve10:Active] config  ssldump -Aed -nni 0.0 port 80
    New TCP connection 1: 172.28.20.17(47893) <-> 172.28.19.252(80)
    1374921475.9033 (0.0011)  C>S
    ---------------------------------------------------------------
    HEAD /frist HTTP/1.1
    Host:
    
    HEAD /second HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    1    1374921475.9034 (0.0000)  C>S  TCP FIN
    New TCP connection 2: 200.200.200.10(47893) <-> 200.200.200.101(80)
    1374921475.9064 (0.0010)  C>S
    ---------------------------------------------------------------
    HEAD /frist HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    1374921475.9082 (0.0018)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    1374921475.9083 (0.0048)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    1374921475.9083 (0.0000)  C>S
    ---------------------------------------------------------------
    HEAD /second HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    2    1374921475.9083 (0.0000)  C>S  TCP FIN
    1374921475.9094 (0.0010)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    1374921475.9094 (0.0010)  S>C
    ---------------------------------------------------------------
    HTTP/1.1 404 Not Found
    Date: Sat, 27 Jul 2013 10:48:26 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    ---------------------------------------------------------------
    
    2    1374921475.9094 (0.0000)  S>C  TCP FIN
    1    1374921475.9094 (0.0000)  S>C  TCP FIN
    
  • But the first request, in which the method saved on httpmethodprev variable, is not rejected.

    Only the subsequent request successfully being rejected.can we count number of keyword (e.g. GET, HEAD) and reject when it occurs more than 1?

    e.g.

    [root@ve10:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.252:80
       ip protocol 6
       rules myrule
       profiles {
          http {}
          tcp {}
       }
    }
    [root@ve10:Active] config  b rule myrule list
    rule myrule {
       when CLIENT_ACCEPTED {
      TCP::collect
    }
    when CLIENT_DATA {
      if { [llength [lsearch -all [TCP::payload] HEAD]] > 1 } {
        reject
        return
      }
      TCP::release
      TCP::collect
    }
    }
    
    [root@ve10:Active] config  ssldump -Aed -nni 0.0 port 80
    New TCP connection 1: 172.28.20.17(47909) <-> 172.28.19.252(80)
    1374923550.5707 (0.0007)  C>S
    ---------------------------------------------------------------
    HEAD /frist HTTP/1.1
    Host:
    
    HEAD /second HTTP/1.1
    Host:
    
    ---------------------------------------------------------------
    
    1    1374923550.5708 (0.0000)  S>C  TCP RST
    
  • doddy's avatar
    doddy
    Icon for Nimbostratus rankNimbostratus

    Hi Kevin & Nitass,,many thanks for helping me with disabling pipelining idea. But I still need to ensure the behavior.

     

    You said that "when pipelining is disabled, bigip will terminate a connection after responding 1st request". Does this mean bigip will close the socket created before to handle the first request? Or does it mean that bigip simply ignore the subsequent request in which delimited with "\r\n" character?

     

     

    Let me add more info regarding my case. So there was HTTP pipeline request that is suspected being used for this purpose:

     

    1. The first request is the legitimate HTTP request, in which requesting the web page that the client truly want to visit

     

    2. The second request (or the third, fourth, and so forth if exist) is used to trick the DPI system, in which read for certain pattern and in fact cannot detect if pipeline is being used.

     

     

    So the bigip is located behind the DPI system on the client perspective.

     

    That is why I need the bigip to detect if the request is in pipeline form or not, and reject the request totally (first and subsequent) if so.

     

    But I cannot implement the CLIENT_ACCEPTED and CLIENT_DATA event as you suggest, since the same VS used currently need to run another HTTP inspection using HTTP_REQUEST event.

     

     

    I will also test the disable pipelining on my network and let you know if the behavior meets my expectation.

     

     

    Thanks again :)

     

  • Does this mean bigip will close the socket created before to handle the first request? Or does it mean that bigip simply ignore the subsequent request in which delimited with "\r\n" character?based on packet trace, bigip sends FIN to both client and server after forwarding 1st response from server to client.

     

     

    But I cannot implement the CLIENT_ACCEPTED and CLIENT_DATA event as you suggest, since the same VS used currently need to run another HTTP inspection using HTTP_REQUEST event.only pipelining request is rejected. HTTP_REQUEST is still triggered by non-pipelining request.
  • doddy's avatar
    doddy
    Icon for Nimbostratus rankNimbostratus
    Hi Nitass, did you mean I can combine TCP level with HTTP level events like this?

     

     

    when CLIENT_ACCEPTED {

     

    TCP::collect

     

    }

     

    when CLIENT_DATA {

     

    TCP::payload parsing and reject command

     

    }

     

    when HTTP_REQUEST {

     

    some existing command

     

    }

     

     

    I didn't know this before, so if it is possible then I think I found what I'm looking for.

     

     

    Thanks :)
  • did you mean I can combine TCP level with HTTP level events like this? yes

    e.g.

    [root@ve10:Active] config  b virtual bar list
    virtual bar {
       snat automap
       pool foo
       destination 172.28.19.252:80
       ip protocol 6
       rules myrule
       profiles {
          http {}
          tcp {}
       }
    }
    [root@ve10:Active] config  b rule myrule list
    rule myrule {
       when CLIENT_ACCEPTED {
      log local0. "CLIENT_ACCEPTED - client [IP::client_addr]:[TCP::client_port]"
      TCP::collect
    }
    when CLIENT_DATA {
      log local0. "CLIENT_DATA - client [IP::client_addr]:[TCP::client_port] payload [TCP::payload]"
      if { [llength [lsearch -all [TCP::payload] HEAD]] > 1 } {
        log local0. "CLIENT_DATA - client [IP::client_addr]:[TCP::client_port] reject"
        reject
        return
      }
      TCP::release
      TCP::collect
    }
    when HTTP_REQUEST {
      log local0. "HTTP_REQUEST - client [IP::client_addr]:[TCP::client_port] request [HTTP::request]"
    }
    }
    
    [root@ve10:Active] config  tail -f /var/log/ltm
    Jul 28 09:09:38 local/tmm info tmm[22008]: Rule myrule : CLIENT_ACCEPTED - client 172.28.20.17:47963
    Jul 28 09:09:38 local/tmm info tmm[22008]: Rule myrule : CLIENT_DATA - client 172.28.20.17:47963 payload HEAD /frist HTTP/1.1  Host:     HEAD /second HTTP/1.1  Host:
    Jul 28 09:09:38 local/tmm info tmm[22008]: Rule myrule : CLIENT_DATA - client 172.28.20.17:47963 reject
    
    Jul 28 09:10:05 local/tmm info tmm[22008]: Rule myrule : CLIENT_ACCEPTED - client 172.28.20.17:47964
    Jul 28 09:10:05 local/tmm info tmm[22008]: Rule myrule : CLIENT_DATA - client 172.28.20.17:47964 payload HEAD /normal HTTP/1.1  User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5  Host: 172.28.19.252  Accept: */*
    Jul 28 09:10:05 local/tmm info tmm[22008]: Rule myrule : HTTP_REQUEST - client 172.28.20.17:47964 request HEAD /normal HTTP/1.1  User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5  Host: 172.28.19.252  Accept: */*
    
  • doddy's avatar
    doddy
    Icon for Nimbostratus rankNimbostratus
    Hi Nitass, glad to hear these events combination works :)

     

    I'm not touching my network to try disabling pipeline yet since it still weekend days, but I think the event combination is exactly what meet my expectations.

     

     

    Thanks a lot for your help, really appreciate that :)