corazawaf / coraza-spoa

EXPERIMENTAL: A wrapper around the OWASP Coraza WAF for HAProxy's SPOE filters
Apache License 2.0
85 stars 18 forks source link

Argument version and headers not found #73

Closed aim0r closed 1 year ago

aim0r commented 1 year ago

Hey there, thank you for aiming to replace Trustwave ModSecurity. I have been following the instruction to setup coraza-spoa with haproxy and finally got it running. I am not seeing it block however.

The agent reports the below on every single request:

INFO[0000] spoe: listening on 127.0.0.1:9000 Argument 'version' not found Argument 'headers' not found

Haproxy log shows the following:

Jul 11 13:15:41 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-frontend-http-request> sid=17 st=0 0/0/0/0/1 1/1 0/0 0/27 Jul 11 13:15:41 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-frontend-http-request> sid=17 st=0 0/0/0/0/1 1/1 0/0 0/27 Jul 11 13:15:41 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-http-response> sid=17 st=0 0/0/0/0/0 1/1 0/0 0/28 Jul 11 13:15:41 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-http-response> sid=17 st=0 0/0/0/0/0 1/1 0/0 0/28 Jul 11 13:15:41 test haproxy[222]: 192.168.1.10:64257 [11/Jul/2023:13:15:41.954] test test_backend/s1 0/0/1/1/0/1/3/6 200 3383 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" 1ec2bbea-a85f-44da-8e21-d7f382b7bc7b spoa-error: - waf-hit: 0 Jul 11 13:15:42 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-frontend-http-request> sid=19 st=0 0/0/0/0/0 1/1 0/0 0/29 Jul 11 13:15:42 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-frontend-http-request> sid=19 st=0 0/0/0/0/0 1/1 0/0 0/29 Jul 11 13:15:42 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-http-response> sid=19 st=0 0/0/0/0/0 1/1 0/0 0/30 Jul 11 13:15:42 test haproxy[222]: SPOE: [coraza-agent] <EVENT:on-http-response> sid=19 st=0 0/0/0/0/0 1/1 0/0 0/30 Jul 11 13:15:42 test haproxy[222]: 192.168.1.10:64257 [11/Jul/2023:13:15:41.961] test test_backend/s1 0/63/0/63/0/0/1/64 404 433 - - ---- 1/1/0/0/0 0/0 "GET /favicon.ico HTTP/1.1" 5bd81c35-f252-4c44-9ac1-22f17983b228 spoa-error: - waf-hit: 0

The haproxy config is defined as in the sample from the git project.

filter spoe engine coraza config /etc/coraza-spoa/coraza.cfg

and

http-request deny if { var(txn.coraza.fail) -m int eq 1 } http-response deny if { var(txn.coraza.fail) -m int eq 1 } http-request deny deny_status 504 if { var(txn.coraza.error) -m int gt 0 } http-response deny deny_status 504 if { var(txn.coraza.error) -m int gt 0 } use_backend test_backend

backend is:

backend test_backend mode http server s1 127.0.0.1:8080

backend coraza-spoa mode tcp server s1 127.0.0.1:9000

This:

curl http://serverip/\?x\=/etc/passwd

Results in the request being passed to apache which is listening on port 8080 same server. Browsing to the url results in the same.

Corerules are loaded and configured as per example in docs.

zc-devs commented 1 year ago
  1. What's the version of coraza-spoa? HAProxy?
  2. What are your config.yaml, coraza.conf, crs-setup.conf?
  3. Have you tried to run in docker?
aim0r commented 1 year ago

Thank you for the prompt response. Requested info below.

1.Version of coraza-spoa: git rev-parse --short HEAD dd5eb86, HAProxy version is 2.4.22-0 on Ubuntu 22.10

2. config.yml is a straight from here: github. Note I had to remove the pipe right behind the "directives:" for it to work and be valid not sure why the pipe is in there in the first place.

haproxy/coraza.cfg is a straight copy from here: github. Only changed the bind to 127.0.0.1 since I don't need it to listen on all ips and changed the log location.

coraza.conf is a straight copy from here: github

crs-setup.conf is a straight copy from here: github. I have also taken the crs-setup directly from coreruleset and the rules from coreruleset with no success.

I have not tried to run it in docker and wasn't planning to. Already running it in a container on Proxmox and don't need the overhead of docker.

zc-devs commented 1 year ago

wasn't planning to. Already running it in a container on Proxmox and don't need the overhead of docker.

That's OK of course, but I meant something different.

I have not tried to run it in docker

I've checked again by running example in docker and haven't got error you described. Works as intended.

Try to run docker example. If it works, try to find difference between docker setup and your standalone.

aim0r commented 1 year ago

I just actually did compare the docker example and the haproxy conf is significantly different from the one in the git for the non docker version. So I copied it over and not getting the Argument missing message anymore but still not blocking.

Do I need to tell it to turn on blocking explicitly or is it on by default? Does it silently drop or does it show the drop in the logs? When it blocks does it also ban subsequent requests for a period of time?

Is the test example outdated maybe and HAProxy already escapes it?

I am using the example from the docs to test.

curl http://localhost:4000/\?x\=/etc/passwd

This request results in: Jul 12 08:56:19 test haproxy[2691]: 192.168.1.10:50526 [12/Jul/2023:08:56:19.013] test test/<NOSRV> 0/0/3/3/-1/-1/-1/3 403 72 - - PR-- 1/1/0/0/0 0/0 "GET /?x=/etc/passwd HTTP/1.1" 2a3af7ac-ffbd-49b0-9274-5e8870bc3bce spoa-error: - waf-hit: -

Just doing curl http://localhost results in

Jul 12 08:56:14 test haproxy[2691]: 192.168.1.10:56796 [12/Jul/2023:08:56:14.481] test test_backend/<NOSRV> 0/0/2/2/-1/-1/-1/2 200 80 - - LR-- 1/1/0/0/3 0/0 "GET / HTTP/1.1" 7b1d9997-a188-4f50-a852-214e3f77c3e0 spoa-error: - waf-hit: 0

waf-hit - on first request and waf-hit 0 on second

Obviously changed ip and port.

Update:

Log statement is wrong:

log-format "%ci:%cp\ [%t]\ %ft\ %b/%s\ %Th/%Ti/%TR/%Tq/%Tw/%Tc/%Tr/%Tt\ %ST\ %B\ %CC\ %CS\ %tsc\ %ac/%fc/%bc/%sc/%rc\ %sq/%bq\ %hr\ %hs\ %{+Q}r\ %ID\ spoa-error:\ %[var(txn.coraza.error)]\ waf-hit:\ %[var(txn.coraza.fail)]"

txn.coraza.fail is always 0 or -

txn.coraza.action is the correct variable to see if denied or passed

changed it and now can see requests being blocked.

This can be closed. The documentation is all over the place about this. Hopefully this will be updated at some point to help others.

Thank you for your help.

zc-devs commented 1 year ago

Do I need to tell it to turn on blocking explicitly or is it on by default?

Sets up by SecRuleEngine

Does it silently drop or does it show the drop in the logs?

In Docker example it shows

When it blocks does it also ban subsequent requests for a period of time?

I don't know, TBH. Look at underlying library. @jcchavezs I'm curious too.

Is the test example outdated maybe and HAProxy already escapes it?

What example? In the docs?

Hopefully this will be updated at some point to help others.

PR is welcome ;)

jcchavezs commented 1 year ago

When it blocks does it also ban subsequent requests for a period of time?

nope, that would be a whole different thing but achievable with current APIs. is this something you need?

All the other answers are right.

aim0r commented 1 year ago

I do not, I was just curious. But it would be cool ;-). I have been running it in DetectionOnly mode now for a few hours and capturing logs to see what I need to tweak in terms of rules. Very excited about this, so far it's working great.

I do have a few more questions:

  1. I believe rules are not live reloaded upon change or additions, is that correct? If no live reload I believe just simple restart of spoa agent should refresh rules.
  2. Any plans on a log parser for it or does someone already have one? Or any advice which ones would be good, looking at coraza-spoa server.log specifically.
  3. Any chance there will be a web frontent at some point similar to HAProxy stats page to edit, change and activate or deactivate rules?
zc-devs commented 1 year ago
  1. There is no live reload #19. Yes, should refresh.
  2. It would be as JSON in near future #70. And Corarza's Audit and Debug logs are in JSON already. At least at high level.
  3. I think, a lot of time will pass before. Is there the one, who wanna implement it?
zc-devs commented 1 year ago

Log statement is wrong txn.coraza.action is the correct variable to see if denied or passed

@aim0r, thanks for report, fixed in #74.

sts commented 1 year ago

I think we should also update the example configs with an updated haproxy config, which incorporates the new variables. Just for reference, this is whats in use for the Docker & e2e tests:

# Currently haproxy cannot use variables to set the code or deny_status, so this needs to be manually configured here
http-request redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
http-response redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }

http-request deny deny_status 403 hdr waf-block "request"  if { var(txn.coraza.action) -m str deny }
http-response deny deny_status 403 hdr waf-block "response" if { var(txn.coraza.action) -m str deny }

http-request silent-drop if { var(txn.coraza.action) -m str drop }
http-response silent-drop if { var(txn.coraza.action) -m str drop }

# Deny in case of an error, when processing with the Coraza SPOA
http-request deny deny_status 504 if { var(txn.coraza.error) -m int gt 0 }
http-response deny deny_status 504 if { var(txn.coraza.error) -m int gt 0 }
zc-devs commented 1 year ago

^ Addressed by #76.

@jcchavezs mark this as a bug, please.