I am trying to set up reporting to AbuseIPDB, which is proving to be much harder than expected. I have the data in Graylog to create a stream and send the data. I need to create a HTTP post:
Hey @jonathanb thanks for asking.I think you can set up reporting to AbuseIPDB in Graylog 5.x using a Graylog pipeline rule.
Generally, hereās how:
Create a new pipeline rule in Graylog and specify the stream you want to use for reporting.
In the pipeline rule, add a rule that matches the specific log events you want to report to AbuseIPDB.
Use the Graylog built-in HTTP Output to create a HTTP POST request to the AbuseIPDB API. You can configure the URL, headers, and parameters as shown in your curl example.
Save the pipeline rule and test it to make sure itās working as expected.
Note: You will need to replace āYOUR_OWN_API_KEYā with your actual API key in the HTTP header.
Yes. Create variables from input data, process them, and then pass them to an HTTP output module where they are formatted and placed into a URL as query parameters or part of the endpoint. The URL is then used to send an HTTP request to a remote server to retrieve or update data.
Here in the community we have some pipeline experts, like @tmacgbay . You may want to reach out to him.
I am trying to read through the example to see what fits.
Trying to write it out then as a start:
rule "AbuseIPDB"
when
has_field("Snort_source_IP") &&
is_null(lookup_value("AbuseIPDB_reported", to_string($message.Snort_source_IP)))
then
let ip = is_ip($message.Snort_source_IP);
let discription = is_string($message.Snort_Description);
let url = to_url(["https://api.abuseipdb.com/api/v2/report?key=diuyef73ubysdvciujqw9h&"ip"&categories=18,22&"discription]);
let setlookup = lookup_set_value("AbuseIPDB_reported",ip,"true");
end
So with the above I am now confused how to call that URL.
It looks like you are interested in querying api.abuseIPDB.com with data from a message field and having the Graylog message contain the results in a separate new field?
The way other queries are done like this is via System/Lookup Tables. There you can start with a Data Adapter⦠they have several built in for things like DNS lookup, GrayNoise, ThreatFox⦠some of which are only available for the licensed version. It looks to me like the closest you can get is by creating a āHTTP JSONPathā adapter, then a Cache and Lookup Table associated with it. I have created lookup tables but I havenāt worked with this adapter. It has some instruction built into the configuration page that looks like it will give you enough to get there⦠more than the online docs.
If you do get it working, it would be super helpful to future readers/searchers if you documented your steps and posted them either here or even better in the rules and templates exchange.
@tmacgbay
I will be setting this up as a content package or providing instructions once working.
The lookup is not to spam reporting every time the IP comes up. So I am writing to a lookup to see if previously reported by my system.
So the removing the lookup the code I need to get 100%:
rule "AbuseIPDB"
when
has_field("Snort_source_IP")
then
let ip = is_ip($message.Snort_source_IP);
let discription = is_string($message.Snort_Description);
let url = to_url(["https://api.abuseipdb.com/api/v2/report?key=diuyef73ubysdvciujqw9h&"ip"&categories=18,22&"discription]);
end
How every the URL doesnāt work either as you need to set headers.
You are trying to send (you said POST) data external to Graylog with a URL that describes the path to send it. If you create a lookup table with the āHTTP JSONPathā Adapter, you can do just that. It will likely return something you are interested in for confirmation or exists/NULL or FQDN or whateverā¦
on a side note you may need to adjust some functions:
let ip = is_ip($message.Snort_source_IP);
Might be to_ip() or even to_string() since the function is_ip() returns a boolean as to whether the Snort_source_IP is an IP or not.
rule "AbuseIPDB"
when
has_field("Snort_source_IP") &&
is_null(lookup_value("AbuseIPDB_reported", to_string($message.Snort_source_IP)))
then
//Get the Offending IP
let ip = to_string($message.Snort_source_IP);
//Get the Snort Description
let discription = to_string($message.Snort_Description);
//Create the IP string
let concatip = concat("ip=",to_string($message.Snort_source_IP));
//Encode the IP
let encodedip = base64url_encode(concatip);
//Create the Comment string
let concatdiscription = concat("comment=",to_string($message.Snort_Description));
let encodeddiscription = base64url_encode(concatdiscription);
//Set Categories
let cat = to_string("categories=18,22");
//Create full request
let reporturl_1 = concat(encodedip,cat);
let reporturl = concat(reporturl_1,encodeddiscription);
//Lookup to report ip
let report = lookup_value("AbuseIPDB_Report", reporturl);
//Below line has an error can not index value
//set_field("abuseConfidenceScore", report["abuseConfidenceScore"]);
let setlookup = lookup_set_value("AbuseIPDB_reported",ip,"true");
end
I have the return error to fix, however, I also need to put quotes (") round the IP address in:
let concatip = concat(āip=ā,to_string($message.Snort_source_IP));
For quotes, you can escape them ⦠I think this would work to put quotes around the IPā¦
let concatip = concat("ip=\"",to_string($message.Snort_source_IP));
let concat_fin = concat(concatip,"\"");
// do something with concat_fin here
Not sure what the return data looks like in āreportā, you can use the debug function to see it show up in the Graylog log fileā¦
// use $ tail -f /var/log/graylog-server/server.log to watch for the results of the below debug message
//
debug(concat("============ results in report: ",to_string(report)));
Right, we are close. I didnāt need āā I checked the API manual.
2023-02-02T18:58:46.754Z INFO [Function] PIPELINE DEBUG: ============ URL report: ip%3D172.16.0.53&categories=18,22%26comment%3DET+SCAN+Suspicious+inbound+to+MSSQL+port+1433
2023-02-02T18:58:46.890Z WARN [HTTPJSONPathDataAdapter] Couldn't read single JSONPath from response - returning empty result (Expected to find an object with property ['data'] in path $ but found 'java.lang.String'. This is not a json object according to the JsonProvider: 'com.jayway.jsonpath.spi.json.JsonSmartJsonProvider'.)
2023-02-02T18:58:46.890Z INFO [Function] PIPELINE DEBUG: ============ results in report:
Code is
rule "AbuseIPDB"
when
has_field("Snort_source_IP") &&
is_null(lookup_value("AbuseIPDB_reported", to_string($message.Snort_source_IP)))
then
//Get the Offending IP
let ip = to_string($message.Snort_source_IP);
//Get the Snort Description
let description = to_string($message.Snort_Description);
//Create the IP string
let concatip = concat("ip=",to_string($message.Snort_source_IP));
//Encode the IP
let encodedip = urlencode(concatip);
//Create the Comment string
let concatdescription = concat("&comment=",description);
let encodeddescription = urlencode(concatdescription);
//Set Categories
let cat = to_string("&categories=18,22");
//Create full request
let reporturl_1 = concat(encodedip,cat);
let reporturl = concat(reporturl_1,encodeddescription);
//Lookup to report ip
debug(concat("============ URL report: ",to_string(reporturl)));
let report = lookup_value("AbuseIPDB_Report", reporturl);
debug(concat("============ results in report: ",to_string(report)));
//Below line has an error can not index value
//set_field("abuseConfidenceScore", report["abuseConfidenceScore"]);
let setlookup = lookup_set_value("AbuseIPDB_reported",ip,"true");
end
The Lookup table is:
URL: https://api.abuseipdb.com/api/v2/report?${key}
Single value JSONPath: $.data.abuseConfidenceScore
HTTP User-Agent: Graylog
HTTP Headers:
NAME VALUE
Accept application/json
Key fvdoijhsrvoinfvbopinfbsdlkn
So somewhere the HTTP is failing. As far as I can tell the URL string is correct from the rule but something is still not right.
May need to adjust what you are passing to be in json format with parse_json()
Of Note:
This is all new territory here for me so donāt take what I am saying to be correct⦠I am guessing as much as or more than you. IT may be that this Data Adapter requires data to be passed as json but that wonāt be the right format for what you want to doā¦
I think you are close, hard to tell where it is off.
Take the debug() results from reporturl and stick it in to the ${key} portion of https://api.abuseipdb.com/api/v2/report?${key}⦠throw all that in a browser and see what you come back with⦠modify that URL line until it comes back with what you want in the browser, then adjust the pipeline rule concat()s to match your modifications.
It then wants a post with data:
ip=IPADDRESS
categories=NUMBERS,NUMBERS
comment=YOURCOMMENT
From what I understand of the lookup it can only pass data in the URL. AbuseIPDB wants the data in the data post (assuming that is the right terminology). As such it would need to be the HTTP Output but I donāt see it as an option.
If you request the URL with all the data the webserver dumps the request.
From my experience the Graylog Open version can only do GET not POST HTTP requests if the API requires POST I think you are out of luck without creating a custom plugin.
@tmacgbay Thank you for all your input on this one. I have learnt a lot about pipeline rules.
Shamefully, I think writing a full plugin is out of my reach and I am going to have to can the idea. I hope that for someone that has the HTTP output there is enough information here to help.
If anyone wants to collaborate on a plugin please contact me as this is a great project for network admins.