owasp-modsecurity / ModSecurity-nginx

ModSecurity v3 Nginx Connector
Apache License 2.0
1.55k stars 281 forks source link

Segfault after hitting rule with SecRuleUpdateTargetById #74

Closed zimmerle closed 5 years ago

zimmerle commented 6 years ago

@slabber commented on Thu Oct 12 2017

I updated a rule by appending to the config: SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/example/"

When I hit this rule the worker process dies with signal 11:

2017/10/12 14:46:29 [alert] 16#16: worker process 27 exited on signal 11

This is with core rule set 3.0.2, libmodsec 3.0.0rc1 and nginx compiled with: nginx version: nginx/1.13.6 built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5) built with OpenSSL 1.0.2g 1 Mar 2016 TLS SNI support enabled configure arguments: --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/ngi nx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-tem p-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-htt p_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_sub_module --with-http_v2_module --with-stream -- with-stream_ssl_module --with-stream_ssl_preread_module --with-threads --with-file-aio --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --without-http_uwsgi_m odule --without-http_scgi_module --with-cc-opt='-g -O3 -flto -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 --param=ssp-buffer-size=4 -DTCP_F ASTOPEN=23 -Wno-error=strict-aliasing -fPIC -m64 -mtune=generic' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now' --add-module=/tmp/build/ngx_devel_kit-0.3.0 --add-module=/tmp/build/set-misc-nginx-module-0.31 --add-module=/tmp/build/nginx-module-vts-0.1.15 --add-module=/tmp/build/headers-more-nginx-module-0.32 --add-module=/tmp/build/nginx-goodi es-nginx-sticky-module-ng-08a395c66e42 --add-module=/tmp/build/nginx-http-auth-digest-7955af9c77598c697ac292811914ce1e2b3b824c --add-module=/tmp/build/ngx_http_substitutions_filter_module-bc 58cb11844bc42735bbaef7085ea86ace46d05b --add-module=/tmp/build/nginx-opentracing-fcc2e822c6dfc7d1f432c16b07dee9437c24236a --add-dynamic-module=/tmp/build/ModSecurity-nginx-a2a5858d249222938c 2f5e48087a922c63d7f9d8


@slabber commented on Thu Oct 12 2017

modsecurity.conf.txt


@zimmerle commented on Fri Oct 20 2017

Hi @slabber

Thanks for the report.

On 93e18ca5ea18659af58a9f23d057917a01b9867d and 30797a458b1f8e42905538219ea75ddc9c719a76 we have changed the way that the parser understands the element selection while using a regex. That changes may affect the problem that you are correctly facing. Do you mind to update to the most recent version of the code and perform the test again?

On the top of that, if you have the backtrace for the segfault it will be very useful. I did not managed to reproduce your problem. On c4fcb36f4cdd941fca413f85f7ff8603f257a3d9 I've made the debug logs a little bit more verbose about variable exclusion, you may want to share the debug logs as well.


@slabber commented on Mon Oct 23 2017

Still the same. CRS 3.0.2 with: SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/Example/" appended

This is a backtrace from 351beb05676ab5dd5687057f38e7cb6c82f198c0

FYI, this is using https://github.com/kubernetes/ingress-nginx/tree/master/images/nginx-slim

Program terminated with signal SIGSEGV, Segmentation fault.
#0  modsecurity::Rule::getFinalVars (this=this@entry=0x5576e09cb100, trans=trans@entry=0x5576d9a48a10) at rule.cc:465
465 rule.cc: No such file or directory.
[Current thread is 1 (Thread 0x7f3ea6121140 (LWP 1250))]
(gdb) backtrace full
#0  modsecurity::Rule::getFinalVars (this=this@entry=0x5576e09cb100, trans=trans@entry=0x5576d9a48a10) at rule.cc:465
        __for_range = <optimized out>
        exclusions = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7ffea918bfe0, _M_prev = 0x7ffea918bfe0}, _M_data = 0}}}, <No data fields>}
        exclusions_update_by_tag_remove = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7ffea918c000, _M_prev = 0x7ffea918c000}, _M_data = 0}}}, <No data fields>}
        exclusions_update_by_id_remove = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7ffea918c020, _M_prev = 0x7ffea918c020}, _M_data = 0}}}, <No data fields>}
        variables = std::vector of length 6, capacity 8 = {0x5576e09c8cc0, 0x5576e09c88b0, 0x5576e09c9590, 0x5576e09c98f0, 0x5576e09c9ad0, 0x5576e09c9bf0}
        finalVars = std::vector of length 0, capacity 0
#1  0x00007f3e9e30ca2d in modsecurity::Rule::evaluate (this=this@entry=0x5576e09cb100, trans=trans@entry=0x5576d9a48a10,
    ruleMessage=std::shared_ptr (count 1, weak 0) 0x5576e0c48eb0) at rule.cc:755
        globalRet = false
        variables = <optimized out>
        recursiveGlobalRet = <optimized out>
        containsDisruptive = false
        finalVars = std::vector of length 0, capacity 0
        eparam = "\"((?:[\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\+\\=\\{\\}\\[\\]\\|\\:\\;\\\"\\'\\\302\264\\\342\200\231\\\342\200\230\\`\\<\\>][^\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\+\\=\\{\\}\\[\\]\\|\\:\\;\\\"\\'\\\302\264\\\342\200\231\\\342\200\230\\`\\<\\>]*?){8})\""
#2  0x00007f3e9e2fede7 in modsecurity::Rules::evaluate (this=0x5576e00b99a0, phase=phase@entry=3, transaction=transaction@entry=0x5576d9a48a10)
    at rules.cc:213
        rule = 0x5576e09cb100
        i = 280
        rules = std::vector of length -11746106468198, capacity -11746106468198 = {0x5576dea83000, 0x5576ddf5a730, 0x5576ddf5afc0, 0x5576dfe3ff80,
          0x5576e00ded80, 0x5576e00d3490, 0x5576e00d3b20, 0x5576e00e06d0, 0x5576e00e0c80, 0x5576e00e1400, 0x5576e00e1c30, 0x5576e00e21b0, 0x5576e00e3400,
          0x5576e00e3870, 0x5576e00e3da0, 0x5576e00e4310, 0x5576e00e4980, 0x5576e00e52a0, 0x5576e00e92f0, 0x5576e00e99d0, 0x5576e00ea190, 0x5576e00ea770,
          0x5576e00ead70, 0x5576e00eb350, 0x5576e00eb9e0, 0x5576e00ec040, 0x5576e00ec670, 0x5576e00ecca0, 0x5576e00dffa0, 0x5576e00ee560, 0x5576e00eeaf0,
          0x5576e00efbc0, 0x5576e00f0160, 0x5576e00f13a0, 0x5576e00f4930, 0x5576e00f4f20, 0x5576e00f5da0, 0x5576e00f6ee0, 0x5576e00f81b0, 0x5576e00f9290,
          0x5576e00fb460, 0x5576e00fb860, 0x5576e00fc8f0, 0x5576e00fdd60, 0x5576e00ff4d0, 0x5576e0102be0, 0x5576e0104c00, 0x5576e0105b30, 0x5576e01069d0,
          0x5576e0108910, 0x5576e0108e20, 0x5576e010ac20, 0x5576e010b2d0, 0x5576e010bc00, 0x5576e010cd80, 0x5576e010f620, 0x5576e0110420, 0x5576e0111860,
          0x5576e0111ed0, 0x5576e01134d0, 0x5576e0114300, 0x5576e0115680, 0x5576e0116930, 0x5576e0117cb0, 0x5576e0118d90, 0x5576e0119650, 0x5576e0119f80,
          0x5576e011ade0, 0x5576e011b980, 0x5576e011c4e0, 0x5576e011cae0, 0x5576e010e850, 0x5576e011eca0, 0x5576e011f640, 0x5576e01201c0, 0x5576e0120da0,
          0x5576e0121380, 0x5576e0124200, 0x5576e012a070, 0x5576e012bbf0, 0x5576e012c7b0, 0x5576e012cf80, 0x5576e00e5a20, 0x5576e012eb90, 0x5576e012fcd0,
          0x5576e01bc4f0, 0x5576e01c7fd0, 0x5576e01c88f0, 0x5576e01dd520, 0x5576e01fa350, 0x5576e01fac40, 0x5576e0217750, 0x5576e0217d50, 0x5576e011da20,
          0x5576e0219cf0, 0x5576e021ab90, 0x5576e021b960, 0x5576e021c920, 0x5576e021e350, 0x5576e021f5d0, 0x5576e0220b10, 0x5576e0222030, 0x5576e02229d0,
          0x5576e0223b10, 0x5576e02250e0, 0x5576e02266b0, 0x5576e0227750, 0x5576e0228710, 0x5576e0229580, 0x5576e0229ba0, 0x5576e022a940, 0x5576e022e1e0,
          0x5576e022fc00, 0x5576e0230570, 0x5576e0231db0, 0x5576e02327c0, 0x5576e0233a90, 0x5576e0234ce0, 0x5576e0235fa0, 0x5576e0237220, 0x5576e02388d0,
          0x5576e0239e30, 0x5576e023b970, 0x5576e023c830, 0x5576e023dfb0, 0x5576e023f120, 0x5576e0240060, 0x5576e0241350, 0x5576e0242900, 0x5576e0243a30,
          0x5576e0246450, 0x5576e0247550, 0x5576e02485b0, 0x5576e0248e80, 0x5576e024a120, 0x5576e024aaa0, 0x5576e024b9e0, 0x5576e024d0c0, 0x5576e024e3a0,
          0x5576e024f6a0, 0x5576e024fc70, 0x5576e0250a20, 0x5576e0251f30, 0x5576e02531b0, 0x5576e02546c0, 0x5576e0255bf0, 0x5576e0256ce0, 0x5576e0257d40,
          0x5576e0259010, 0x5576e0259970, 0x5576e025ad20, 0x5576e025b620, 0x5576e025bff0, 0x5576e025cf50, 0x5576e025e090, 0x5576e02626e0, 0x5576e0263670,
          0x5576e0264cc0, 0x5576e0266560, 0x5576e049c5b0, 0x5576e0267600, 0x5576e0267f70, 0x5576e02689f0, 0x5576e054a520, 0x5576e054ab20, 0x5576e0218be0,
          0x5576e054cbb0, 0x5576e054de40, 0x5576e054edd0, 0x5576e054f5a0, 0x5576e0550440, 0x5576e05515b0, 0x5576e0552130, 0x5576e0552740, 0x5576e054bb10,
          0x5576e0554da0, 0x5576e055b850, 0x5576e0556490, 0x5576e0558f30, 0x5576e055e6d0, 0x5576e055fc20, 0x5576e05de290, 0x5576e05df610, 0x5576e05e0cc0,
          0x5576e05e1ea0, 0x5576e05f4ad0, 0x5576e05f5480, 0x5576e05f6020, 0x5576e05f6bc0, 0x5576e05f73c0, 0x5576e05f8410, 0x5576e05f9af0, 0x5576e05fade0,
          0x5576e0684600, 0x5576e06aaef0, 0x5576e06b1f70, 0x5576e06b3480, 0x5576e06b3f00, 0x5576e06c9c60, 0x5576e06cb220...}
#3  0x00007f3e9e2e8cb1 in modsecurity::Transaction::processRequestBody (this=0x5576d9a48a10) at transaction.cc:808
        a = std::unique_ptr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >> containing 0x0
        fullRequest = "host: www.example.com\ncache-control: max-age=0\nuser-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\ndnt: 1\nupgr"...
        l = std::vector of length 8, capacity 8 = {0x5576da571630, 0x5576da571590, 0x5576da571460, 0x5576da5713c0, 0x5576d40b5e00, 0x5576d40b5d20,
          0x5576e0c487d0, 0x5576e0c48af0}
#4  0x00007f3e9e5fc9dc in ngx_http_modsecurity_pre_access_handler () from /etc/nginx/modules/ngx_http_modsecurity_module.so
No symbol table info available.
#5  0x00005576d2261b83 in ngx_http_core_generic_phase ()
No symbol table info available.
#6  0x00005576d225d855 in ngx_http_core_run_phases ()
No symbol table info available.
#7  0x00005576d2245f4e in ngx_http_process_request ()
No symbol table info available.
#8  0x00005576d220ce48 in ngx_http_v2_state_header_complete.part.18.lto_priv ()
No symbol table info available.
#9  0x00005576d21eded0 in ngx_http_v2_read_handler.lto_priv ()
No symbol table info available.
#10 0x00005576d2256551 in ngx_epoll_process_events.lto_priv ()
No symbol table info available.
#11 0x00005576d22584df in ngx_process_events_and_timers ()
No symbol table info available.
#12 0x00005576d2269915 in ngx_worker_process_cycle ()
No symbol table info available.
#13 0x00005576d22658c9 in ngx_spawn_process ()
No symbol table info available.
#14 0x00005576d226636e in ngx_start_worker_processes ()
No symbol table info available.
#15 0x00005576d2267bb9 in ngx_master_process_cycle ()
No symbol table info available.
#16 0x00005576d21a82c1 in main ()
No symbol table info available.
(gdb)

@slabber commented on Mon Oct 23 2017

The last entry in the debug log at level 5 is:

[4] (Rule: 942420) Executing operator "Rx" with param "((?:[\~!\@#\$\%\^\&*()-+\={}[]|\:\;\"\'\´\’\‘`\\>][^\~\!\@\#\$\%\^\&\*\(\)\-\+\=\{\}\[\]\|\:\;\"\'\´\’\‘\`\<\]*?){8})" against REQUEST_COOKIES|REQUEST_COOKIES_NAMES, except for: REQUEST_COOKIES:regex(utm)|REQUEST_COOKIES:regex(_pk_ref)|REQUEST_COOKIES:regex(utm)|REQUEST_COOKIES:regex(_pk_ref).

There is no mention of the exception added with SecRuleUpdateTargetById

In this example, the appended lines were:

SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:/Example\./"
SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/Example\./"

@zimmerle commented on Tue Oct 24 2017

Hi @slabber,

Thank you for the very detailed report. Should be fixed by 371fc03218efc205e8e42935c7d95b82c6047676. It will be great if you can confirm.


@slabber commented on Tue Oct 24 2017

Still segfault:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  modsecurity::Rule::getFinalVars (this=this@entry=0x55ab0dc60750, trans=trans@entry=0x55ab0d360c20) at rule.cc:465
465         if (a.second->m_isExclusion) {
[Current thread is 1 (Thread 0x7f7b5ae30140 (LWP 106))]
(gdb) backtrace full
#0  modsecurity::Rule::getFinalVars (this=this@entry=0x55ab0dc60750, trans=trans@entry=0x55ab0d360c20) at rule.cc:465
        __for_range = <optimized out>
        exclusions = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7fff25d7e4a0, _M_prev = 0x7fff25d7e4a0}, _M_data = 0}}}, <No data fields>}
        exclusions_update_by_tag_remove = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7fff25d7e4c0, _M_prev = 0x7fff25d7e4c0}, _M_data = 0}}}, <No data fields>}
        exclusions_update_by_id_remove = {<std::__cxx11::_List_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {
            _M_impl = {<std::allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<__gnu_cxx::new_allocator<std::_List_node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >> = {<No data fields>}, <No data fields>},
              _M_node = {<std::__detail::_List_node_base> = {_M_next = 0x7fff25d7e4e0, _M_prev = 0x7fff25d7e4e0}, _M_data = 0}}}, <No data fields>}
        variables = std::vector of length 6, capacity 8 = {0x55ab0dc5e310, 0x55ab0dc5df00, 0x55ab0dc5ebe0, 0x55ab0dc5ef40, 0x55ab0dc5f120, 0x55ab0dc5f240}
        finalVars = std::vector of length 0, capacity 0
#1  0x00007f7b5301cded in modsecurity::Rule::evaluate (this=this@entry=0x55ab0dc60750, trans=trans@entry=0x55ab0d360c20,
    ruleMessage=std::shared_ptr (count 1, weak 0) 0x55ab0130bfb0) at rule.cc:755
        globalRet = false
        variables = <optimized out>
        recursiveGlobalRet = <optimized out>
        containsDisruptive = false
        finalVars = std::vector of length 0, capacity 0
        eparam = "\"((?:[\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\+\\=\\{\\}\\[\\]\\|\\:\\;\\\"\\'\\\302\264\\\342\200\231\\\342\200\230\\`\\<\\>][^\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\+\\=\\{\\}\\[\\]\\|\\:\\;\\\"\\'\\\302\264\\\342\200\231\\\342\200\230\\`\\<\\>]*?){8})\""
#2  0x00007f7b5300ede7 in modsecurity::Rules::evaluate (this=0x55ab0d34efb0, phase=phase@entry=3, transaction=transaction@entry=0x55ab0d360c20)
    at rules.cc:213
        rule = 0x55ab0dc60750
        i = 280
        rules = std::vector of length -11774130250994, capacity -11774130250994 = {0x55ab0d0d5980, 0x55ab0d0d5dd0, 0x55ab0bd18340, 0x55ab0bd18930,
          0x55ab0d374400, 0x55ab0d368aa0, 0x55ab0d369170, 0x55ab0d375d50, 0x55ab0d376300, 0x55ab0d376a80, 0x55ab0d3772b0, 0x55ab0d377830, 0x55ab0d378a80,
          0x55ab0d378ef0, 0x55ab0d379420, 0x55ab0d379990, 0x55ab0d37a000, 0x55ab0d37a920, 0x55ab0d37e970, 0x55ab0d37f050, 0x55ab0d37f810, 0x55ab0d37fdf0,
          0x55ab0d3803f0, 0x55ab0d3809d0, 0x55ab0d381060, 0x55ab0d3816c0, 0x55ab0d381cf0, 0x55ab0d382320, 0x55ab0d3755f0, 0x55ab0d383b80, 0x55ab0d3840f0,
          0x55ab0d385260, 0x55ab0d385780, 0x55ab0d386a40, 0x55ab0d389fd0, 0x55ab0d38a5c0, 0x55ab0d38b440, 0x55ab0d38c580, 0x55ab0d38d850, 0x55ab0d38e930,
          0x55ab0d390b00, 0x55ab0d390f00, 0x55ab0d391f90, 0x55ab0d393400, 0x55ab0d394b70, 0x55ab0d398280, 0x55ab0d39a2a0, 0x55ab0d39b1d0, 0x55ab0d39c070,
          0x55ab0d39dfb0, 0x55ab0d39e4c0, 0x55ab0d3a02c0, 0x55ab0d3a0970, 0x55ab0d3a12a0, 0x55ab0d3a2430, 0x55ab0d3a4cd0, 0x55ab0d3a5ad0, 0x55ab0d3a6f10,
          0x55ab0d3a7580, 0x55ab0d3a8b80, 0x55ab0d3a99b0, 0x55ab0d3aad30, 0x55ab0d3abfe0, 0x55ab0d3ad360, 0x55ab0d3ae440, 0x55ab0d3aed00, 0x55ab0d3af630,
          0x55ab0d3b0490, 0x55ab0d3b1030, 0x55ab0d3b1b90, 0x55ab0d3b2190, 0x55ab0d3a3ef0, 0x55ab0d3b4350, 0x55ab0d3b4cf0, 0x55ab0d3b5870, 0x55ab0d3b6450,
          0x55ab0d3b6b10, 0x55ab0d3b98b0, 0x55ab0d3bf720, 0x55ab0d3c12a0, 0x55ab0d3c1e60, 0x55ab0d3c2630, 0x55ab0d37b0a0, 0x55ab0d3c4220, 0x55ab0d3c5300,
          0x55ab0d451ba0, 0x55ab0d45d670, 0x55ab0d45df90, 0x55ab0d472bc0, 0x55ab0d48f9f0, 0x55ab0d4902e0, 0x55ab0d4acdf0, 0x55ab0d4ad330, 0x55ab0d3b3140,
          0x55ab0d4af430, 0x55ab0d4b02a0, 0x55ab0d4b1030, 0x55ab0d4b1ff0, 0x55ab0d4b3a30, 0x55ab0d4b4cb0, 0x55ab0d4b6160, 0x55ab0d4b7680, 0x55ab0d4b8040,
          0x55ab0d4b9180, 0x55ab0d4ba750, 0x55ab0d4bbd20, 0x55ab0d4bcdc0, 0x55ab0d4bdd80, 0x55ab0d4bebf0, 0x55ab0d4bf210, 0x55ab0d4bffb0, 0x55ab0d4c3850,
          0x55ab0d4c5270, 0x55ab0d4c5be0, 0x55ab0d4c7420, 0x55ab0d4c7e30, 0x55ab0d4c9100, 0x55ab0d4ca350, 0x55ab0d4cb610, 0x55ab0d4cc890, 0x55ab0d4cdf40,
          0x55ab0d4cf490, 0x55ab0d4d0fd0, 0x55ab0d4d1e90, 0x55ab0d4d3610, 0x55ab0d4d4780, 0x55ab0d4d56c0, 0x55ab0d4d69b0, 0x55ab0d4d7f60, 0x55ab0d4d9090,
          0x55ab0d4dbab0, 0x55ab0d4dcbb0, 0x55ab0d4ddc10, 0x55ab0d4de4e0, 0x55ab0d4df780, 0x55ab0d4e0100, 0x55ab0d4e1040, 0x55ab0d4e2720, 0x55ab0d4e3a00,
          0x55ab0d4e4d00, 0x55ab0d4e52d0, 0x55ab0d4e6080, 0x55ab0d4e7590, 0x55ab0d4e8810, 0x55ab0d4e9d20, 0x55ab0d4eb250, 0x55ab0d4ec340, 0x55ab0d4ed3a0,
          0x55ab0d4ee670, 0x55ab0d4eefd0, 0x55ab0d4f0380, 0x55ab0d4f0c80, 0x55ab0d4f1650, 0x55ab0d4f65d0, 0x55ab0d4f7740, 0x55ab0d4f7cf0, 0x55ab0d4ae310,
          0x55ab0d4fa340, 0x55ab0d4fbbb0, 0x55ab0d731c00, 0x55ab0d4fcc50, 0x55ab0d4fd5c0, 0x55ab0d4fe040, 0x55ab0d7dfb70, 0x55ab0d7e0170, 0x55ab0d4f8bf0,
          0x55ab0d7e2260, 0x55ab0d7e34c0, 0x55ab0d7e4480, 0x55ab0d7e4be0, 0x55ab0d7e5b20, 0x55ab0d7e6c20, 0x55ab0d7e77b0, 0x55ab0d7e7dc0, 0x55ab0d7e1170,
          0x55ab0d7ea430, 0x55ab0d7f0ed0, 0x55ab0d7ebb20, 0x55ab0d7ee5c0, 0x55ab0d7f3d50, 0x55ab0d7f52a0, 0x55ab0d8738f0, 0x55ab0d874c70, 0x55ab0d876320,
          0x55ab0d877500, 0x55ab0d88a130, 0x55ab0d88aae0, 0x55ab0d88b680, 0x55ab0d88c220, 0x55ab0d88ca20, 0x55ab0d88da40, 0x55ab0d88f140, 0x55ab0d890430,
          0x55ab0d919c40, 0x55ab0d940530, 0x55ab0d9475b0, 0x55ab0d948ac0, 0x55ab0d949540, 0x55ab0d95f290, 0x55ab0d960850...}
#3  0x00007f7b52ff8cb1 in modsecurity::Transaction::processRequestBody (this=0x55ab0d360c20) at transaction.cc:808
        a = std::unique_ptr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >> containing 0x0
        fullRequest = "host: www.example.com\ncache-control: max-age=0\nuser-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\ndnt: 1\nupgr"...
        l = std::vector of length 8, capacity 8 = {0x55ab0130c3a0, 0x55ab0130c300, 0x55ab0130c1d0, 0x55ab0130c130, 0x55ab0130c0b0, 0x55ab0130bfd0,
          0x55ab06cf20d0, 0x55ab06cf2410}

@slabber commented on Tue Oct 24 2017

I also still see nothing in the debug log for the exemptions:

[4] (Rule: 942420) Executing operator "Rx" with param "((?:[\~\!\@\#\$\%\^\&\*\(\)\-\+\=\{\}\[\]\|\:\;\"\'\´\�~@~Y\�~@~X\`\<\>][^\~\!\@\#\$\%\^\&\*\(\)\-\+\=\{{
\}\[\]\|\:\;\"\'\´\�~@~Y\�~@~X\`\<\>]*?){8})" against REQUEST_COOKIES|REQUEST_COOKIES_NAMES, except for: REQUEST_COOKIES:regex(__utm)|REQUEST_COOKIES:regex(_pkk
_ref)|REQUEST_COOKIES:regex(__utm)|REQUEST_COOKIES:regex(_pk_ref).

I can also confirm that this is with 371fc03218efc205e8e42935c7d95b82c6047676


@zimmerle commented on Tue Oct 24 2017

@slabber are you using threads on nginx?


@slabber commented on Tue Oct 24 2017

Here's the build script from kubernetes ingress:

#!/bin/bash

# Copyright 2015 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

export NGINX_VERSION=1.13.6
export NDK_VERSION=0.3.0
export VTS_VERSION=0.1.15
export SETMISC_VERSION=0.31
export STICKY_SESSIONS_VERSION=08a395c66e42
export MORE_HEADERS_VERSION=0.32
export NGINX_DIGEST_AUTH=7955af9c77598c697ac292811914ce1e2b3b824c
export NGINX_SUBSTITUTIONS=bc58cb11844bc42735bbaef7085ea86ace46d05b
export NGINX_OPENTRACING=5fa9fd9643efed5f638d0e14c63b5da99a89c7fe
export OPENTRACING_CPP=57a523922941be74569e7173c3f90e556177ec3c
export ZIPKIN_CPP=ca9597495b35194e0a7d910f1e0e74844ee26730
export MODSECURITY=a2a5858d249222938c2f5e48087a922c63d7f9d8

export BUILD_PATH=/tmp/build

export NGINX_OPENTRACING_VENDOR="ZIPKIN"

ARCH=$(uname -p)

get_src()
{
  hash="$1"
  url="$2"
  f=$(basename "$url")

  curl -sSL "$url" -o "$f"
  echo "$hash  $f" | sha256sum -c - || exit 10
  tar xzf "$f"
  rm -rf "$f"
}

mkdir "$BUILD_PATH"
cd "$BUILD_PATH"

if [[ ${ARCH} == "ppc64le" ]]; then
  apt-get update && apt-get install --no-install-recommends -y software-properties-common
fi

# install required packages to build
apt-get update && apt-get install --no-install-recommends -y \
  bash \
  build-essential \
  curl ca-certificates \
  libgeoip1 \
  libgeoip-dev \
  patch \
  libpcre3 \
  libpcre3-dev \
  libssl-dev \
  zlib1g \
  zlib1g-dev \
  libaio1 \
  libaio-dev \
  openssl \
  libperl-dev \
  cmake \
  util-linux \
  wget \
  libcurl4-openssl-dev \
  procps \
  git gdb vim g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libgeoip-dev libtool dh-autoreconf libxml2 libpcre++-dev libxml2-dev \
  linux-headers-generic || exit 1

mkdir -p /etc/nginx

# download GeoIP databases
wget -O /etc/nginx/GeoIP.dat.gz https://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz || { echo 'Could not download GeoLiteCountry, exiting.' ; exit 1; }
wget -O /etc/nginx/GeoLiteCity.dat.gz https://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz || { echo 'Could not download GeoLiteCity, exiting.' ; exit 1; }

gunzip -f /etc/nginx/GeoIP.dat.gz
gunzip -f /etc/nginx/GeoLiteCity.dat.gz

# download, verify and extract the source files
get_src 8512fc6f986a20af293b61f33b0e72f64a72ea5b1acbcc790c4c4e2d6f63f8f8 \
        "http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz"

get_src 88e05a99a8a7419066f5ae75966fb1efc409bad4522d14986da074554ae61619 \
        "https://github.com/simpl/ngx_devel_kit/archive/v$NDK_VERSION.tar.gz"

get_src 97946a68937b50ab8637e1a90a13198fe376d801dc3e7447052e43c28e9ee7de \
        "https://github.com/openresty/set-misc-nginx-module/archive/v$SETMISC_VERSION.tar.gz"

get_src 5112a054b1b1edb4c0042a9a840ef45f22abb3c05c68174e28ebf483164fb7e1 \
        "https://github.com/vozlt/nginx-module-vts/archive/v$VTS_VERSION.tar.gz"

get_src c6d9dab8ea1fc997031007e2e8f47cced01417e203cd88d53a9fe9f6ae138720 \
        "https://github.com/openresty/headers-more-nginx-module/archive/v$MORE_HEADERS_VERSION.tar.gz"

get_src 53e440737ed1aff1f09fae150219a45f16add0c8d6e84546cb7d80f73ebffd90 \
        "https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/get/$STICKY_SESSIONS_VERSION.tar.gz"

get_src 9b1d0075df787338bb607f14925886249bda60b6b3156713923d5d59e99a708b \
        "https://github.com/atomx/nginx-http-auth-digest/archive/$NGINX_DIGEST_AUTH.tar.gz"

get_src 618551948ab14cac51d6e4ad00452312c7b09938f59ebff4f93875013be31f2d \
        "https://github.com/yaoweibin/ngx_http_substitutions_filter_module/archive/$NGINX_SUBSTITUTIONS.tar.gz"

get_src 7de6589e0c6e748ae1d1a2667c40224c5a5a14623b98b4103de9ae5313c4f8db \
        "https://github.com/opentracing-contrib/nginx-opentracing/archive/$NGINX_OPENTRACING.tar.gz"

get_src 367636ed8211fe5d8a9db56014471923165b907f9338e2b871ed4f3c443d7dfe \
        "https://github.com/opentracing/opentracing-cpp/archive/$OPENTRACING_CPP.tar.gz"

get_src cf4ebe742d7fbcc4c2f2510ab03d19f1a765ef764935ce0a53e71e9a0bd7244a \
        "https://github.com/rnburn/zipkin-cpp-opentracing/archive/$ZIPKIN_CPP.tar.gz"

get_src 3abdecedb5bf544eeba8c1ce0bef2da6a9f064b216ebbe20b68894afec1d7d80 \
        "https://github.com/SpiderLabs/ModSecurity-nginx/archive/$MODSECURITY.tar.gz"

#https://blog.cloudflare.com/optimizing-tls-over-tcp-to-reduce-latency/
curl -sSL -o nginx__dynamic_tls_records.patch https://raw.githubusercontent.com/cloudflare/sslconfig/master/patches/nginx__1.11.5_dynamic_tls_records.patch

# build opentracing lib
cd "$BUILD_PATH/opentracing-cpp-$OPENTRACING_CPP"
mkdir .build
cd .build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
make install

# build zipkin lib
cd "$BUILD_PATH/zipkin-cpp-opentracing-$ZIPKIN_CPP"
mkdir .build
cd .build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 ..
make
make install

cd "$BUILD_PATH"

if [[ ${ARCH} == "x86_64" ]]; then
  # build modsecurity library
  git clone https://github.com/SpiderLabs/ModSecurity
  cd ModSecurity/
  git checkout -b v3/master origin/v3/master
  sh build.sh
  git submodule init
  git submodule update
  autoreconf -i
  automake
  autoconf
  ./configure
  make
  make install
fi

# build nginx
cd "$BUILD_PATH/nginx-$NGINX_VERSION"

echo "Applying nginx patches..."
patch -p1 < $BUILD_PATH/nginx__dynamic_tls_records.patch

WITH_FLAGS="--with-debug \
  --with-pcre-jit \
  --with-http_ssl_module \
  --with-http_stub_status_module \
  --with-http_realip_module \
  --with-http_auth_request_module \
  --with-http_addition_module \
  --with-http_dav_module \
  --with-http_geoip_module \
  --with-http_gzip_static_module \
  --with-http_sub_module \
  --with-http_v2_module \
  --with-stream \
  --with-stream_ssl_module \
  --with-stream_ssl_preread_module \
  --with-threads"

if [[ ${ARCH} != "armv7l" || ${ARCH} != "aarch64" ]]; then
  WITH_FLAGS+=" --with-file-aio"
fi

CC_OPT='-g -O0 -flto -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 --param=ssp-buffer-size=4 -DTCP_FASTOPEN=23 -Wno-error=strict-aliasing -fPIC'
LD_OPT='-Wl,-Bsymbolic-functions -fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now'

if [[ ${ARCH} == "x86_64" ]]; then
  CC_OPT+=' -m64 -mtune=generic'
fi

WITH_MODULES="--add-module=$BUILD_PATH/ngx_devel_kit-$NDK_VERSION \
  --add-module=$BUILD_PATH/set-misc-nginx-module-$SETMISC_VERSION \
  --add-module=$BUILD_PATH/nginx-module-vts-$VTS_VERSION \
  --add-module=$BUILD_PATH/headers-more-nginx-module-$MORE_HEADERS_VERSION \
  --add-module=$BUILD_PATH/nginx-goodies-nginx-sticky-module-ng-$STICKY_SESSIONS_VERSION \
  --add-module=$BUILD_PATH/nginx-http-auth-digest-$NGINX_DIGEST_AUTH \
  --add-module=$BUILD_PATH/ngx_http_substitutions_filter_module-$NGINX_SUBSTITUTIONS \
  --add-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING/opentracing \
  --add-module=$BUILD_PATH/nginx-opentracing-$NGINX_OPENTRACING/zipkin"

if [[ ${ARCH} == "x86_64" ]]; then
  WITH_MODULES+=" --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx-$MODSECURITY"
fi

./configure \
  --prefix=/usr/share/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --http-log-path=/var/log/nginx/access.log \
  --error-log-path=/var/log/nginx/error.log \
  --lock-path=/var/lock/nginx.lock \
  --pid-path=/run/nginx.pid \
  --http-client-body-temp-path=/var/lib/nginx/body \
  --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
  --http-proxy-temp-path=/var/lib/nginx/proxy \
  --http-scgi-temp-path=/var/lib/nginx/scgi \
  --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
  ${WITH_FLAGS} \
  --without-mail_pop3_module \
  --without-mail_smtp_module \
  --without-mail_imap_module \
  --without-http_uwsgi_module \
  --without-http_scgi_module \
  --with-cc-opt="${CC_OPT}" \
  --with-ld-opt="${LD_OPT}" \
  ${WITH_MODULES} \
  && make || exit 1 \
  && make install || exit 1

if [[ ${ARCH} == "x86_64" ]]; then
  mkdir -p /etc/nginx/modules/
  cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
fi

echo "Cleaning..."

cd /

apt-mark unmarkauto \
  bash \
  curl ca-certificates \
  libgeoip1 \
  libpcre3 \
  zlib1g \
  libaio1 \
  xz-utils \
  geoip-bin \
  libyajl2 liblmdb0 libxml2 libpcre++ \
  gzip \
  openssl

apt-get remove -y --purge \
  build-essential \
  gcc-5 \
  cpp-5 \
  libgeoip-dev \
  libpcre3-dev \
  libssl-dev \
  zlib1g-dev \
  libaio-dev \
  linux-libc-dev \
  perl-modules-5.22 \
  cmake \
  wget \
  git g++ pkgconf flex bison doxygen libyajl-dev liblmdb-dev libgeoip-dev libtool dh-autoreconf libpcre++-dev libxml2-dev \
  linux-headers-generic

apt-get autoremove -y

mkdir -p /var/lib/nginx/body /usr/share/nginx/html

mv /usr/share/nginx/sbin/nginx /usr/sbin

#rm -rf "$BUILD_PATH"
rm -Rf /usr/share/man /usr/share/doc
#rm -rf /tmp/* /var/tmp/*
rm -rf /var/lib/apt/lists/*
rm -rf /var/cache/apt/archives/*
rm -rf /usr/local/modsecurity/bin
rm -rf /usr/local/modsecurity/include
rm -rf /usr/local/modsecurity/lib/libmodsecurity.a

# Download owasp modsecurity crs
cd /etc/nginx/
curl -sSL -o master.tgz https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.2/master.tar.gz
tar zxpvf master.tgz
mv owasp-modsecurity-crs-3.0.2/ owasp-modsecurity-crs
rm master.tgz

cd owasp-modsecurity-crs
mv crs-setup.conf.example crs-setup.conf
mv rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
mv rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
cd ..

# Download modsecurity.conf
mkdir modsecurity
cd modsecurity
curl -sSL -o modsecurity.conf https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended

# OWASP CRS v3 rules
echo "
Include /etc/nginx/owasp-modsecurity-crs/crs-setup.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-901-INITIALIZATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-905-COMMON-EXCEPTIONS.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-910-IP-REPUTATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-911-METHOD-ENFORCEMENT.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-912-DOS-PROTECTION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-913-SCANNER-DETECTION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-921-PROTOCOL-ATTACK.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-931-APPLICATION-ATTACK-RFI.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-933-APPLICATION-ATTACK-PHP.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-950-DATA-LEAKAGES.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-951-DATA-LEAKAGES-SQL.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-952-DATA-LEAKAGES-JAVA.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-953-DATA-LEAKAGES-PHP.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-954-DATA-LEAKAGES-IIS.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-959-BLOCKING-EVALUATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-980-CORRELATION.conf
Include /etc/nginx/owasp-modsecurity-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
" > /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf

@slabber commented on Tue Oct 24 2017

So, yes. Threading is enabled by the build script from the kubernetes ingress guys.


@slabber commented on Wed Oct 25 2017

I have recompiled and retested without threads in nginx with exactly the same results and backtrace.


@victorhora commented on Sun Oct 29 2017

Hi @slabber

I tried to mimic your scenario with that build script to reproduce the issue and I think I'm pretty close:

root@ubuntu:/usr/share/nginx/logs# nginx -V
nginx version: nginx/1.13.6
built by gcc 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
built with OpenSSL 1.0.2g  1 Mar 2016
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gzip_static_module --with-http_sub_module --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-threads --with-file-aio --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --without-http_uwsgi_module --without-http_scgi_module --with-cc-opt='-g -O0 -flto -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 --param=ssp-buffer-size=4 -DTCP_FASTOPEN=23 -Wno-error=strict-aliasing -fPIC -m64 -mtune=generic' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -fPIC -pie -Wl,-z,relro -Wl,-z,now' --add-module=/tmp/build/ngx_devel_kit-0.3.0 --add-module=/tmp/build/set-misc-nginx-module-0.31 --add-module=/tmp/build/nginx-module-vts-0.1.15 --add-module=/tmp/build/headers-more-nginx-module-0.32 --add-module=/tmp/build/nginx-goodies-nginx-sticky-module-ng-08a395c66e42 --add-module=/tmp/build/nginx-http-auth-digest-7955af9c77598c697ac292811914ce1e2b3b824c --add-module=/tmp/build/ngx_http_substitutions_filter_module-bc58cb11844bc42735bbaef7085ea86ace46d05b --add-module=/tmp/build/nginx-opentracing-5fa9fd9643efed5f638d0e14c63b5da99a89c7fe/opentracing --add-module=/tmp/build/nginx-opentracing-5fa9fd9643efed5f638d0e14c63b5da99a89c7fe/zipkin --add-dynamic-module=/tmp/build/ModSecurity-nginx-a2a5858d249222938c2f5e48087a922c63d7f9d8

By adding different combinations of the following:

SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:/Example\./"
SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/Example\./"

SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:/example/"
SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/example/"

SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:/Example/"
SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:/Example/"

I still couldn't reproduce this segfault.

But one thing I notice is that on the latest build I can't get SecRuleUpdateTargetById to work properly with regexes. But I could get working properly with

SecRuleUpdateTargetById 942420 "!REQUEST_COOKIES:Example"
SecRuleUpdateTargetById 942421 "!REQUEST_COOKIES:Example"

And I can see the following entry in the debug logs:

[9] Variable: REQUEST_COOKIES:Example is part of the exclusion list (from update by ID), skipping...

But do notice that you only get this entry on the debug logs if there's any matching rule ID about to be triggered. This means that, on PL3 or PL4 you would need to send a request like this:

curl -i -s -k -X $'GET' -H $'Content-Type: text/html' -b $'Example=blah*********' $'http://localhost/

It would be helpful if you could share:

a) The actual full HTTP request that triggers the segfault b) Full audit logs & Debug logs c) ModSecurity configuration file d) CRS configuration file (which Paranoia level you're running?) e) Nginx configuration file (which modules you have enabled?)

Thanks for the report.


@slabber commented on Mon Oct 30 2017

OK, here is a heavily redacted config and it won't work unless you create the certs needed for SSL. I haven't had a chance to check if this specific redacted version crashes or not but read the next comment for my strange findings:

load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;

daemon off;

worker_processes 2;
pid /run/nginx.pid;

worker_rlimit_nofile 523264;

worker_rlimit_core  600M;
working_directory   /tmp/;

worker_shutdown_timeout 10s ;

events {
    multi_accept        on;
    worker_connections  16384;
    use                 epoll;
}

http {

    real_ip_header      X-Forwarded-For;

    real_ip_recursive   on;

    set_real_ip_from    0.0.0.0/0;

    geoip_country       /etc/nginx/GeoIP.dat;
    geoip_city          /etc/nginx/GeoLiteCity.dat;
    geoip_proxy_recursive on;

    sendfile            on;

    aio                 on;
    directio            512;
    output_buffers      1 128k;
    aio_write           on;

    tcp_nopush          on;
    tcp_nodelay         on;

    log_subrequest      on;

    reset_timedout_connection on;

    keepalive_timeout  75s;
    keepalive_requests 100;

    client_header_buffer_size       1k;
    client_header_timeout           60s;
    large_client_header_buffers     4 8k;
    client_body_buffer_size         8k;
    client_body_timeout             60s;

    http2_max_field_size            4k;
    http2_max_header_size           16k;

    types_hash_max_size             2048;
    server_names_hash_max_size      1024;
    server_names_hash_bucket_size   64;
    map_hash_bucket_size            64;

    proxy_headers_hash_max_size     512;
    proxy_headers_hash_bucket_size  64;

    variables_hash_bucket_size      128;
    variables_hash_max_size         2048;

    underscores_in_headers          off;
    ignore_invalid_headers          on;

    include /etc/nginx/mime.types;
    default_type text/html;

    gzip on;
    gzip_comp_level 5;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component;
    gzip_proxied any;

    # Custom headers for response

    add_header Referrer-Policy            "no-referrer";

    add_header X-Content-Type-Options            "nosniff";

    add_header X-Frame-Options            "SAMEORIGIN";

    add_header X-Xss-Protection            "1; mode=block";

    server_tokens off;

    # disable warnings
    uninitialized_variable_warn off;

    # Additional available variables:
    # $namespace
    # $ingress_name
    # $service_name
    log_format upstreaminfo '$the_real_ip - [$the_real_ip] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status';

    map $request_uri $loggable {

        default 1;
    }

    access_log /var/log/nginx/access.log upstreaminfo if=$loggable;

    error_log  /var/log/nginx/error.log notice;

    resolver 10.27.240.10 valid=30s;

    # Retain the default nginx handling of requests without a "Connection" header
    map $http_upgrade $connection_upgrade {
        default          upgrade;
        ''               close;
    }

    map $http_x_forwarded_for $the_real_ip {

        default          $remote_addr;

    }

    # trust http_x_forwarded_proto headers correctly indicate ssl offloading
    map $http_x_forwarded_proto $pass_access_scheme {
        default          $http_x_forwarded_proto;
        ''               $scheme;
    }

    map $http_x_forwarded_port $pass_server_port {
        default           $http_x_forwarded_port;
        ''                $server_port;
    }

    map $http_x_forwarded_host $best_http_host {
        default          $http_x_forwarded_host;
        ''               $this_host;
    }

    map $pass_server_port $pass_port {
        443              443;
        default          $pass_server_port;
    }

    geo $the_real_ip $deny_0b1da094ae5f44a69f942a79dad2ba78 {
        default 1;

        10.0.0.0/8 0;
    }

    # Obtain best http host
    map $http_host $this_host {
        default          $http_host;
        ''               $host;
    }

    server_name_in_redirect off;
    port_in_redirect        off;

    ssl_protocols TLSv1.2;

    # turn on session caching to drastically improve performance

    ssl_session_cache builtin:1000 shared:SSL:10m;
    ssl_session_timeout 10m;

    # allow configuring ssl session tickets
    ssl_session_tickets on;

    # slightly reduce the time-to-first-byte
    ssl_buffer_size 4k;

    # allow configuring custom ssl ciphers
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;

    # allow custom DH file http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam
    ssl_dhparam /ingress-controller/ssl/kube-system-lb-dhparam.pem;

    ssl_ecdh_curve auto;

    proxy_ssl_session_reuse on;

    upstream nonprod-portal-int-9999 {
        # Load balance algorithm; empty for round robin, which is the default

        least_conn;

        keepalive 32;

        server 10.24.0.6:9999 max_fails=0 fail_timeout=0;

    }

    server {
        server_name example.com ;

        listen 80;

        listen [::]:80;

        set $proxy_upstream_name "-";

        listen 443  ssl http2;

        listen [::]:443  ssl http2;

        # PEM sha: a426527480e6626d41e8489e598d523c2ad8c862
        ssl_certificate                         /ingress-controller/ssl/example.pem;
        ssl_certificate_key                     /ingress-controller/ssl/example.pem;

        ssl_trusted_certificate                 /ingress-controller/ssl/example-full-chain.pem;
        ssl_stapling                            on;
        ssl_stapling_verify                     on;

        more_set_headers                        "Strict-Transport-Security: max-age=15724800; includeSubDomains;";

        location / {

            set $proxy_upstream_name "nonprod-portal-int-9999";

            set $namespace      "nonprod";
            set $ingress_name   "mvc.int";
            set $service_name   "";

            # enforce ssl on server side
            if ($pass_access_scheme = http) {
                return 301 https://$best_http_host$request_uri;
            }

            modsecurity on;

            modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

            if ($deny_0b1da094ae5f44a69f942a79dad2ba78) {
                return 403;
            }

            port_in_redirect off;

            client_max_body_size                    "1m";

            proxy_set_header Host                   $best_http_host;

            # Pass the extracted client certificate to the backend

            # Allow websocket connections
            proxy_set_header                        Upgrade           $http_upgrade;
            proxy_set_header                        Connection        $connection_upgrade;

            proxy_set_header X-Real-IP              $the_real_ip;
            proxy_set_header X-Forwarded-For        $the_real_ip;
            proxy_set_header X-Forwarded-Host       $best_http_host;
            proxy_set_header X-Forwarded-Port       $pass_port;
            proxy_set_header X-Forwarded-Proto      $pass_access_scheme;
            proxy_set_header X-Original-URI         $request_uri;
            proxy_set_header X-Scheme               $pass_access_scheme;

            # Pass the original X-Forwarded-For
            proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

            # mitigate HTTPoxy Vulnerability
            # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
            proxy_set_header Proxy                  "";

            # Custom headers to proxied server

            proxy_connect_timeout                   5s;
            proxy_send_timeout                      60s;
            proxy_read_timeout                      60s;

            proxy_redirect                          off;
            proxy_buffering                         off;
            proxy_buffer_size                       "4k";
            proxy_buffers                           4 "4k";
            proxy_request_buffering                 "on";

            proxy_http_version                      1.1;

            proxy_cookie_domain                     off;
            proxy_cookie_path                       off;

            # In case of errors try the next upstream server before returning an error
            proxy_next_upstream                     error timeout invalid_header http_502 http_503 http_504;

            proxy_pass http://nonprod-portal-int-9999;

        }

    }
}

@slabber commented on Mon Oct 30 2017

So with the above, the lines that seem to cause the segfault are the "if" sections both before and after the inclusion of the modsecurity configs. i.e.

            # enforce ssl on server side
            if ($pass_access_scheme = http) {
                return 301 https://$best_http_host$request_uri;
            }

and

            if ($deny_0b1da094ae5f44a69f942a79dad2ba78) {
                return 403;
            }

If either of these are included then segfault still occurs. With both removed everything works as expected. Here is the curl line which is pretty much as you comment above:

curl -i -s -k -X $'GET' -H $'Content-Type: text/html' -b $'Example=blah*****' -H $'Host: example.com' $'https://localhost:443/'


@victorhora commented on Tue Oct 31 2017

Thanks @slabber

With this configuration file I can confirm the segfault occurring with the Nginx directive below enabled:

 # enforce ssl on server side
            if ($pass_access_scheme = http) {
                return 301 https://$best_http_host$request_uri;
            }

And a SecRuleUpdateTargetByID rule with any existing ID such as:

SecRuleUpdateTargetById 200000 "!ARGS:foo"

In this case any request triggers the segfault.


@slabber commented on Wed Nov 08 2017

@victorhora Any update on this? It's highly blocking for us kubernetes users. Even perhaps some update as to when you expect this to be fixed would be useful.

Thanks!

zimmerle commented 6 years ago

Confirmed that this issue depending on have Nginx configured with a set of 3rd party modules. Not able to reproduce the issue in a plain version of ModSecurity.

ghost commented 6 years ago

Thanks @zimmerle . I guess at this stage I will just unpick the build script of my nginx container until I find which specific flag / module / patch is causing it.

ghost commented 6 years ago

@zimmerle Still crashing. I have simplified the setup to help you reproduce and also removed all 3rd party modules and patches from the build script. Nginx is now built like this:

./configure \
  --prefix=/usr/share/nginx \
  --conf-path=/etc/nginx/nginx.conf \
  --modules-path=/etc/nginx/modules \
  --http-log-path=/var/log/nginx/access.log \
  --error-log-path=/var/log/nginx/error.log \
  --lock-path=/var/lock/nginx.lock \
  --pid-path=/run/nginx.pid \
  --http-client-body-temp-path=/var/lib/nginx/body \
  --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
  --http-proxy-temp-path=/var/lib/nginx/proxy \
  --http-scgi-temp-path=/var/lib/nginx/scgi \
  --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
  --with-http_ssl_module \
  --without-mail_pop3_module \
  --without-mail_smtp_module \
  --without-mail_imap_module \
  --without-http_uwsgi_module \
  --without-http_scgi_module \
  --add-dynamic-module=$BUILD_PATH/ModSecurity-nginx-$MODSECURITY \
  && make || exit 1 \
  && make install || exit 1

Nginx config file is now:

load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;

daemon off;

worker_processes 2;
pid /run/nginx.pid;

worker_rlimit_nofile 523264;

events {
    worker_connections  16384;
}

http {
    sendfile            on;
    keepalive_timeout  75s;
    include /etc/nginx/mime.types;
    default_type text/html;
    error_log  /var/log/nginx/error.log notice;

    server {
        server_name _;

        listen 80 default_server;

        location / {
            set $dummy 0;
            if ($dummy) {
                return 301 http://google.com;
            }

            modsecurity on;
            modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

            proxy_pass http://google.com:80/;
        }
    }
}

Reminder, the modsecurity_rules_file must be appended with a SecRuleUpdateTargetById

If I remove the if block it also stops crashing.

zimmerle commented 6 years ago

Hi @slabber,

I am re-opening the issue. I appreciate the detailed description, unfortunately, due to reasons bigger then my desire, I cannot work on that issue at this moment.

zimmerle commented 5 years ago

As of ModSecurity's commit: fa5f3784f24442ef64114aa57090fa5f1395a2e4 this is no longer an issue.