Rules: Need to match same source ip from two sources with different field name for same value

1,390 views
Skip to first unread message

María A

unread,
May 10, 2022, 1:09:05 PM5/10/22
to Wazuh mailing list
Hello team,

I need to generate an alert when a Suricata network scan is detected and later a successful Web server attack is detected as well.

I am struggling creating the rules:

<rule id="300001" level="3" frequency="2" timeframe="120">
<if_matched_sid>86601</if_matched_sid>
<match>ET SCAN</match>
<description>Multiple network scan detected</description>
<group>multiple_scan</group>
</rule>

<rule id="300002" level="3">
<if_sid>31106</if_sid>
<match>200</match>
<description>Successful web-server attack</description>
<group>success_attack</group>
</rule>

<rule id="300003" level="12" timeframe="120">
<if_group>success_attack</if_group> --> Don't know if this is Ok
<if_matched_group>multiple_scan</if_matched_group>  --> Don't know if this is Ok
 <---field to match?--->
<description>Successful web-server attack after Suricata scan detected</description>
<group>intrusion</group>
</rule>

My problem is that source ip from suricata and web_accesslog are different (src_ip and srcip) and I can't find the way to get rule 300003 fired.  
 <same_srcip /> or <same_source_ip /> is not working.

Sorry if this is an easy one, but I can't find the solution.
Thank you!


Christian Borla

unread,
May 12, 2022, 4:01:16 PM5/12/22
to Wazuh mailing list
Hi Maria A!
I hope you are doing fine!

It's not an easy one, there is a way that may helps to match ips but it's not so pretty.
I focused to make works the two different source ips, looking for rule and decoders that trigger your custom rules, I found that Suricata events are json events.

Running an example Suricata event on wazuh-logtest

{"timestamp":"2016-05-02T17:46:48.515262+0000","flow_id":1234,"in_iface":"eth0","event_type":"alert","src_ip":"16.10.10.10","src_port":5555,"dest_ip":"16.10.10.11","dest_port":80,"proto":"TCP","alert":{"action":"allowed","gid":1,"signature_id":2019236,"rev":3,"signature":"ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number","category":"Attempted Administrator Privilege Gain","severity":1},"payload":"abcde","payload_printable":"hi test","stream":0,"host":"suricata.com"}

**Phase 1: Completed pre-decoding.

**Phase 2: Completed decoding.
    name: 'json'
    alert.action: 'allowed'
    alert.category: 'Attempted Administrator Privilege Gain'
    alert.gid: '1'
    alert.rev: '3'
    alert.severity: '1'
    alert.signature: 'ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number'
    alert.signature_id: '2019236'
    dest_ip: '16.10.10.11'
    dest_port: '80'
    event_type: 'alert'
    flow_id: '1234'
    host: 'suricata.com'
    in_iface: 'eth0'
    payload: 'abcde'
    payload_printable: 'hi test'
    proto: 'TCP'
    src_ip: '16.10.10.10'
    src_port: '5555'
    stream: '0'
    timestamp: '2016-05-02T17:46:48.515262+0000'

**Phase 3: Completed filtering (rules).
    id: '86601'
    level: '3'
    description: 'Suricata: Alert - ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number'
    groups: '['ids', 'suricata']'
    firedtimes: '1'
    mail: 'False'
**Alert to be generated.


Json decoder assigned the variables names as the json has, for this case src_ip: '16.10.10.10', a workaround of this behavior is include a new decoder which will capture and fill srcip field from src_ip.
The file that contain the json decoder is /var/ossec/ruleset/decoders/0006-json_decoders.xml, I replaced the original decoder by customized decoder. (be careful in this section) I don't like modify default files as 0006-json_decoders.xml, but I couldn't make it work otherwise.

Original decoder:

<decoder name="json">
  <prematch>^{\s*"</prematch>
  <plugin_decoder>JSON_Decoder</plugin_decoder>
</decoder>


Customized decoder:

<decoder name="json">
  <prematch>^{\s*"</prematch>
</decoder>

<decoder name="json_child">
 <parent>json</parent>
 <regex type="pcre2">"src_ip":"([^"]+)".*?"host":"suricata</regex>
 <order>srcip</order>
</decoder>

<decoder name="json_child">
  <parent>json</parent>
  <plugin_decoder>JSON_Decoder</plugin_decoder>
</decoder>


Now running wazuh-logtest and same Suricata event.

{"timestamp":"2016-05-02T17:46:48.515262+0000","flow_id":1234,"in_iface":"eth0","event_type":"alert","src_ip":"16.10.10.10","src_port":5555,"dest_ip":"16.10.10.11","dest_port":80,"proto":"TCP","alert":{"action":"allowed","gid":1,"signature_id":2019236,"rev":3,"signature":"ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number","category":"Attempted Administrator Privilege Gain","severity":1},"payload":"abcde","payload_printable":"hi test","stream":0,"host":"suricata.com"}

**Phase 1: Completed pre-decoding.

**Phase 2: Completed decoding.
    name: 'json'
    alert.action: 'allowed'
    alert.category: 'Attempted Administrator Privilege Gain'
    alert.gid: '1'
    alert.rev: '3'
    alert.severity: '1'
    alert.signature: 'ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number'
    alert.signature_id: '2019236'
    dest_ip: '16.10.10.11'
    dest_port: '80'
    event_type: 'alert'
    flow_id: '1234'
    host: 'suricata.com'
    in_iface: 'eth0'
    payload: 'abcde'
    payload_printable: 'hi test'
    proto: 'TCP'
    src_ip: '16.10.10.10'
    src_port: '5555'
    srcip: '16.10.10.10'
    stream: '0'
    timestamp: '2016-05-02T17:46:48.515262+0000'

**Phase 3: Completed filtering (rules).
    id: '86601'
    level: '3'
    description: 'Suricata: Alert - ET WEB_SERVER Possible CVE-2014-6271 Attempt in HTTP Version Number'
    groups: '['ids', 'suricata']'
    firedtimes: '1'
    mail: 'False'
**Alert to be generated.

I found srcip and src_ip, both with same information, I just split in 2 the original decoder, and create a new decoder that capture src_ip section if there is a suricata name in the host
"src_ip":"([^"]+)".*?"host":"suricata .
I guess that way you can use <same_srcip /> configuration.

Let me know if this information is useful to you.
Regards.

María A

unread,
May 13, 2022, 3:24:38 PM5/13/22
to Wazuh mailing list
Hi Christian!

Thank you so much for your help, you are great!! I have made one change to adapt the decoder to my json output from Suricata and is working fine:

 <regex type="pcre2">"src_ip":"([^"]+)".*?"alert"</regex> (Just "guessing", but works)

Now I have a different problem. The last rule is still not firing. I have tested with logtest to check what happens:

( If you think this is a different question, please, let me know and I'll post a new one in the group)


1 - First Suricata scan:
{"timestamp":"2022-05-13T17:18:12.271704+0200","flow_id":713546383238488,"in_iface":"enp0s3","event_type":"alert","src_ip":"192.168.8.55","src_port":36113,"dest_ip":"192.168.8.58","dest_port":3306,"proto":"TCP","alert":{"action":"allowed","gid":1,"signature_id":2010937,"rev":3,"signature":"ET SCAN Suspicious inbound to mySQL port 3306","category":"Potentially Bad Traffic","severity":2,"metadata":{"created_at":["2010_07_30"],"former_category":["HUNTING"],"updated_at":["2018_03_27"]}},"flow":{"pkts_toserver":1,"pkts_toclient":0,"bytes_toserver":60,"bytes_toclient":0,"start":"2022-05-13T17:18:12.271704+0200"}}

(...)

**Phase 3: Completed filtering (rules).
    id: '86601'
    level: '3'
    description: 'Suricata: Alert - ET SCAN Suspicious inbound to mySQL port 3306' -----> OK

    groups: '['ids', 'suricata']'
    firedtimes: '1'
    mail: 'False'

2 - Second Suricata scan within 30 seconds:

(...)

**Phase 3: Completed filtering (rules).
    id: '300001'
    level: '3'
    description: 'Multiple network scan detected'  -------> OK, first of my custom rules
    groups: '['correlated_rules', 'multiple_scan']'
    firedtimes: '1'
    frequency: '2'
    mail: 'False'

3 - Web-server 'attack':

**Phase 1: Completed pre-decoding.
    full event: '{"timestamp":"2022-05-13T20:08:30.343+0200","rule":{"level":6,"description":"A web attack returned code 200 (success).","id":"31106","mitre":{"id":["T1190"],"tactic":["Initial Access"],"technique":["Exploit Public-Facing Application"]},"firedtimes":3,"mail":false,"groups":["web","accesslog","attack"],"pci_dss":["6.5","11.4"],"gdpr":["IV_35.7.d"],"nist_800_53":["SA.11","SI.4"],"tsc":["CC6.6","CC7.1","CC8.1","CC6.1","CC6.8","CC7.2","CC7.3"]},"agent":{"id":"002","name":"Ubuntu","ip":"192.168.8.61"},"manager":{"name":"siem"},"id":"1652465310.12452","full_log":"127.0.0.1 - - [13/May/2022:20:08:29 +0200] \"GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1\" 200 4158","decoder":{"name":"web-accesslog"},"data":{"protocol":"GET","srcip":"127.0.0.1","id":"200","url":"/vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit"},"location":"/opt/lampp/logs/access_log"}'


**Phase 2: Completed decoding.
    name: 'json'
    agent.id: '002'
    agent.ip: '192.168.8.61'
    agent.name: 'Ubuntu'
    data.id: '200'
    data.protocol: 'GET'
    data.srcip: '127.0.0.1'
    data.url: '/vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit'
    decoder.name: 'web-accesslog'
    full_log: '127.0.0.1 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158'
    id: '1652465310.12452'
    location: '/opt/lampp/logs/access_log'
    manager.name: 'siem'
    rule.description: 'A web attack returned code 200 (success).'
    rule.firedtimes: '3'
    rule.gdpr: '['IV_35.7.d']'
    rule.groups: '['web', 'accesslog', 'attack']'
    rule.id: '31106'
    rule.level: '6'
    rule.mail: 'false'
    rule.mitre.id: '['T1190']'
    rule.mitre.tactic: '['Initial Access']'
    rule.mitre.technique: '['Exploit Public-Facing Application']'
    rule.nist_800_53: '['SA.11', 'SI.4']'
    rule.pci_dss: '['6.5', '11.4']'
    rule.tsc: '['CC6.6', 'CC7.1', 'CC8.1', 'CC6.1', 'CC6.8', 'CC7.2', 'CC7.3']'
    timestamp: '2022-05-13T20:08:30.343+0200'


**Phase 3: Completed filtering (rules).
    id: '1002'
    level: '2'
    description: 'Unknown problem somewhere in the system.'  ---> The problem with json format, I guess?, but I can see the "Successful web-server attack" alert in events, the second rule.
    groups: '['syslog', 'errors']'
    firedtimes: '1'
    gpg13: '['4.3']'
    mail: 'False'

4 - But if I test in logtest with the full-log content (not json format), it works:

192.168.8.55 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158

**Phase 1: Completed pre-decoding.
    full event: '192.168.8.55 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158'

**Phase 2: Completed decoding.
    name: 'web-accesslog'
    id: '200'
    protocol: 'GET'
    srcip: '192.168.8.55'
    url: '/vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit'


**Phase 3: Completed filtering (rules).
    id: '300003'
    level: '12'
    description: 'Suricata scan followed by successful web-server attack' --------> The rule that I need to be fired.
    groups: '['correlated_rules', 'intrusion']'
    firedtimes: '1'
    frequency: '2'
    mail: 'True'
**Alert to be generated.
 
These are my rules to test:

<rule id="300001" level="3" frequency="2" timeframe="30">
    <decoded_as>json</decoded_as>

    <if_matched_sid>86601</if_matched_sid>
    <match>ET SCAN</match>
    <description>Multiple network scan detected</description> --> Alert fired in events
    <group>multiple_scan,</group>
</rule>

<rule id="300002" level="12">

    <if_sid>31106</if_sid>
    <match>200</match>
    <description>Successful web-server attack</description>  --> Alert fired in events instead the third rule.
    <group>success_attack,</group>

</rule>

<rule id="300003" level="12" timeframe="120">
    <if_group>success_attack</if_group>
    <if_matched_group>multiple_scan</if_matched_group>
    <same_srcip />
    <description>Suricata scan followed by successful web-server attack</description> --> Only visible with logtest with 'full_log' content
    <group>intrusion,</group>
</rule>

The web-server agent has a group configuration to get server logs:

<agent_config>
    <!-- Shared agent configuration here -->
    <localfile>
        <log_format>apache</log_format>
        <location>/opt/lampp/logs/access_log</location>
    </localfile>
</agent_config>

I don't know if I is there an easy solution for this or I need to create decoders (sigh)
Suricata and this web-server 'super attack' are just to know how can I correlate data from different sources. I would like to create alerts for more complex scenarios, but I think is not easy to me this way. May be is there another way to accomplish what I need?


Thank you so much for your help, Christian!!

Christian Borla

unread,
May 16, 2022, 3:47:47 PM5/16/22
to Wazuh mailing list
Hi Maria!
You are welcome! thanks for use Wazuh, I hope you are doing well.
Sorry for the delay.

Just for test I did a change to your custom rule

<rule id="300003" level="12" timeframe="120">
 <if_group>success_attack</if_group>
 <if_matched_sid>300001</if_matched_sid>                                                                                 <---- I use the id to make it trigger and works too.

 <description>Successful web-server attack after Suricata scan detected</description>
 <group>intrusion</group>
</rule>

Same as your test, running twice

{"timestamp":"2022-05-13T17:18:12.271704+0200","flow_id":713546383238488,"in_iface":"enp0s3","event_type":"alert","src_ip":"192.168.8.55","src_port":36113,"dest_ip":"192.168.8.58","dest_port":3306,"proto":"TCP","alert":{"action":"allowed","gid":1,"signature_id":2010937,"rev":3,"signature":"ET SCAN Suspicious inbound to mySQL port 3306","category":"Potentially Bad Traffic","severity":2,"metadata":{"created_at":["2010_07_30"],"former_category":["HUNTING"],"updated_at":["2018_03_27"]}},"flow":{"pkts_toserver":1,"pkts_toclient":0,"bytes_toserver":60,"bytes_toclient":0,"start":"2022-05-13T17:18:12.271704+0200"}}

And running one

192.168.8.55 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158

I got:

**Phase 3: Completed filtering (rules).
    id: '300003'
    level: '12'
    description: 'Successful web-server attack after Suricata scan detected'
    groups: '['local', 'syslog', 'sshd', 'intrusion']'

    firedtimes: '1'
    frequency: '2'
    mail: 'True'
**Alert to be generated.

My question is, Is it correct use a full alert in log test? I always test it with full log section, in this example

{"timestamp":"2022-05-13T20:08:30.343+0200","rule":{"level":6,"description":"A web attack returned code 200 (success).","id":"31106","mitre":{"id":["T1190"],"tactic":["Initial Access"],"technique":["Exploit Public-Facing Application"]},"firedtimes":3,"mail":false,"groups":["web","accesslog","attack"],"pci_dss":["6.5","11.4"],"gdpr":["IV_35.7.d"],"nist_800_53":["SA.11","SI.4"],"tsc":["CC6.6","CC7.1","CC8.1","CC6.1","CC6.8","CC7.2","CC7.3"]},"agent":{"id":"002","name":"Ubuntu","ip":"192.168.8.61"},"manager":{"name":"siem"},"id":"1652465310.12452","full_log":"127.0.0.1 - - [13/May/2022:20:08:29 +0200] \"GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1\" 200 4158","decoder":{"name":"web-accesslog"},"data":{"protocol":"GET","srcip":"127.0.0.1","id":"200","url":"/vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit"},"location":"/opt/lampp/logs/access_log"}

the full_log section is (it escape the double quotes before GET)

127.0.0.1 - - [13/May/2022:20:08:29 +0200] \"GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1\" 200 4158

It will look like:


127.0.0.1 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158

Same result as

192.168.8.55 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158


**Phase 1: Completed pre-decoding.
    full event: '127.0.0.1 - - [13/May/2022:20:08:29 +0200] "GET /vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit HTTP/1.1" 200 4158'


**Phase 2: Completed decoding.
    name: 'web-accesslog'
    id: '200'
    protocol: 'GET'
    srcip: '127.0.0.1'

    url: '/vulnerabilities/sqli/?id=%3Fid%3Da%27+UNION+SELECT+%22text1%22%2C%22text2%22%3B--+-%26Submit%3DSubmit&Submit=Submit'

**Phase 3: Completed filtering (rules).
    id: '300002'
    level: '3'
    description: 'Successful web-server attack'
    groups: '['local', 'syslog', 'sshd', 'success_attack']'
    firedtimes: '4'

    mail: 'False'
**Alert to be generated.

Events before been processed should be in /var/ossec/logs/archive/archives.json or archives.log (archives.json to be sure)
If archives file doesn't exist, double check manager ossec.conf include log all options as following configuration, and restart the server.

    <ossec_config>
        <global>
             <alerts_log>yes</alerts_log>
             <logall>yes</logall>
             <logall_json>no</logall_json>
        </global>


Anyway, to match that alert log with a rule we can continues from rule 1002, because is the last rule that match it.

**Phase 3: Completed filtering (rules).
    id: '1002'
    level: '2'
    description: 'Unknown problem somewhere in the system.'
    groups: '['syslog', 'errors']'
    firedtimes: '1'
    gpg13: '['4.3']'
    mail: 'False'

I did a custom rule:

<rule id="300000" level="5">
    <if_sid>1002</if_sid>
    <field name="full_log" type="pcre2">(?:\d{1,3}\.){3}\d{1,3}.*?GET\s+\S+\s+HTTP.*?200\s+\d+</field>
    <description>test rule</description>
    <options>no_full_log</options>
    <group>intrusion,</group>
</rule>

The regex look for an valid IP at beginning (?:\d{1,3}\.){3}\d{1,3}, then the GET word, then HTTP following by a 200.
(?:\d{1,3}\.){3}\d{1,3}.*?GET\s+\S+\s+HTTP.*?200\s+\d+

And the result is:

**Phase 3: Completed filtering (rules).
    id: '300000'
    level: '7'
    description: 'test rule'
    groups: '['local', 'syslog', 'sshd', 'intrusion']'
    firedtimes: '1'
    mail: 'False'

At this point it's possible use this new custom rule to trigger rule 300002, or create a another rule (example 300005) that fires by  300002 or 300000, and change 300003 to fires with  300005. But rule 300000 doesn't include the srcip field.  
Could you check if it's mandatory use the full alert?, in that case we can try to make another decoder, to make it fit.

Let me know if this information is useful to you.
Regards!

María A

unread,
May 23, 2022, 6:06:32 AM5/23/22
to Wazuh mailing list
Hello Christian, sorry for the delay!

I have included your custom rule and now the last rule is getting fired! t-h-a-n-k y-o-u so much!! 

*Phase 3: Completed filtering (rules).
    id: '300003'
    level: '12'
    description: 'Successful web-server attack after Suricata scan detected'
    groups: '['correlate', 'intrusion']'

    firedtimes: '1'
    frequency: '2'
    mail: 'True'

Is it possible to correlate events like these more easily in the last Wazuh version? 

Thank you again, Christian!


Reply all
Reply to author
Forward
0 new messages