Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LdapQuery Analyzer #589

Merged
merged 11 commits into from
Jan 21, 2021
62 changes: 62 additions & 0 deletions analyzers/LdapQuery/LdapQuery.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "Ldap_Query",
"version": "2.0",
"author": "Florian Perret @cyber_pescadito",
"url": "https://github.com/cyberpescadito/Cortex-Analyzers/tree/master/analyzers/LdapQuery",
"license": "AGPL-V3",
"description": "Query your LDAP server to harvest informations about an user of your organization",
"dataTypeList": ["username", "mail"],
"command": "LdapQuery/ldapQuery.py",
"baseConfig": "LdapQuery",
"configurationItems": [
{
"name": "LDAP_address",
"description": "Should contain the protocol. Eg: ldaps://myldap.myorg.com",
"type": "string",
"multi": false,
"required": true
},
{
"name": "LDAP_port",
"description": "Should contain the ldap port. Eg: 389 or 636",
"type": "string",
"multi": false,
"required": true
},
{
"name": "LDAP_username",
"description": "Usernae of the account that will be used to bind to LDAP server. The Account should have permissions to read ldap objects and attributes.",
"type": "string",
"multi": false,
"required": true
},
{
"name": "LDAP_password",
"description": "Password of the account used to bind to LDAP server.",
"type": "string",
"multi": false,
"required": true
},
{
"name": "base_DN",
"description": "The base DN to use in your LDAP. Eg: dc=myorg,dc=com",
"type": "string",
"multi": false,
"required": true
},
{
"name": "uid_search_field",
"description": "Specify here the field to use when searching by username. Eg: uid or sAMAccountName",
"type": "string",
"multi": false,
"required": true
},
{
"name": "attributes",
"description": "Specify here the attributes you want to harvest. Eg: mail",
"type": "string",
"multi": true,
"required": true
}
]
}
100 changes: 100 additions & 0 deletions analyzers/LdapQuery/ldapQuery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
# Author: @cyber_pescadito
import json
from cortexutils.analyzer import Analyzer
import ldap3
from ldap3 import Server, Connection, SIMPLE, SYNC, SUBTREE, ALL


class LdapQuery(Analyzer):
def __init__(self):
Analyzer.__init__(self)
ldap_address = self.get_param(
"config.LDAP_address", None, "ldap_address is missing"
)
ldap_port = self.get_param("config.LDAP_port", None, "ldap_port is missing")
ldap_port = int(ldap_port)

username = self.get_param("config.LDAP_username", None, "username is missing")
password = self.get_param("config.LDAP_password", None, "password is missing")
self.base_dn = self.get_param("config.base_DN", None, "base_dn is missing")
uid_search_field = self.get_param(
"config.search_field", None, "uid_search_field is missing"
)
if self.data_type == "mail":
self.search_field = "mail"
else:
self.search_field = uid_search_field

self.attributes = self.get_param(
"config.attributes", None, "Missing attributes list to report"
)
try:
s = Server(
ldap_address,
port=ldap_port,
get_info=ALL,
use_ssl=True if ldap_port == 636 else False,
)
self.connection = Connection(
s,
auto_bind=True,
client_strategy=SYNC,
user=username,
password=password,
authentication=SIMPLE,
check_names=True,
)
except Exception:
self.error("Error during LDAP connection")

def summary(self, raw):
taxonomies = []
level = "info"
namespace = "LDAP"
predicate = "Query"

# Find a value to return in value attribute of taxonomies object
for user in raw["results"]:
if user.get("o", None):
value = user["o"]
elif user.get("cn", None):
value = user["cn"]
elif user.get("mail", None):
value = user["mail"]
else:
value = "success"

taxonomies.append(self.build_taxonomy(level, namespace, predicate, value))
return {"taxonomies": taxonomies}

def run(self):
# Checking connection to LDAP
Analyzer.run(self)
try:

data = self.get_param("data", None, "Data is missing")
q = "({}={})".format(self.search_field, data)

self.connection.search(self.base_dn, q, SUBTREE, attributes=self.attributes)
responses = self.connection.response

users = []
if responses:
for response in responses:
dict_response = response.get("attributes", None)
user = {}
if dict_response:
for att in dict_response.keys():
user[att] = dict_response[att]
users.append(user)

self.connection.unbind()

self.report({"results": users})
except Exception as e:
self.error(str(e))


if __name__ == "__main__":
LdapQuery().run()
2 changes: 2 additions & 0 deletions analyzers/LdapQuery/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cortexutils
ldap3
28 changes: 28 additions & 0 deletions thehive-templates/LdapQuery_1_0/long.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<div class="report-LdapQuery" ng-if="success">
<style>
.report-LdapQuery dl {
margin-bottom: 2px;
}
</style>

<div class="panel panel-info">
<div class="panel-heading">
<strong>LDAP Query Summary</strong>
</div>
<div class="panel-body">
<div ng-if="content.results.length === 0">
No records found
</div>
<div ng-if="content.results.length > 0">
<div ng-repeat="results in content.results">
<dl class="dl-horizontal" ng-repeat="(key, value) in results">
<dt>{{key}}: </dt>
<dd class="wrap">{{value}}</dd>
</dl>
<hr/>
</div>
</div>
</div>
</div>

</div>
6 changes: 6 additions & 0 deletions thehive-templates/LdapQuery_1_0/short.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<span class="label" ng-repeat="t in content.taxonomies"
ng-class="{'info': 'label-info', 'safe': 'label-success',
'suspicious': 'label-warning',
'malicious':'label-danger'}[t.level]">
{{t.namespace}}:{{t.predicate}}={{t.value}}
</span>