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

Blacklist tagging #211

Merged
merged 7 commits into from Nov 2, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 42 additions & 17 deletions natlas-server/app/admin/routes.py
Expand Up @@ -7,7 +7,9 @@
from app.models import User, ScopeItem, ConfigItem, NatlasServices, AgentConfig, Tag
from app.auth.email import send_user_invite_email
from app.auth.wrappers import isAuthenticated, isAdmin
import ipaddress, hashlib
import ipaddress
import hashlib


@bp.route('/', methods=['GET', 'POST'])
@isAuthenticated
Expand All @@ -19,11 +21,12 @@ def admin():
for fieldname, fieldvalue in configForm.data.items():
if fieldname.upper() in ["SUBMIT", "CSRF_TOKEN"]:
continue
if fieldname.upper() == "ELASTICSEARCH_URL" and fieldvalue != current_app.config["ELASTICSEARCH_URL"]: # if we've got a new elasticsearch address, update our current handle to elastic
# if we've got a new elasticsearch address, update our current handle to elastic
if fieldname.upper() == "ELASTICSEARCH_URL" and fieldvalue != current_app.config["ELASTICSEARCH_URL"]:
current_app.elastic = Elastic(fieldvalue)
current_app.config[fieldname.upper()] = fieldvalue
confitem = ConfigItem.query.filter_by(name=fieldname.upper()).first()
confitem.value=str(fieldvalue)
confitem.value = str(fieldvalue)
db.session.add(confitem)
0xdade marked this conversation as resolved.
Show resolved Hide resolved
db.session.commit()
return render_template("admin/index.html", configForm=configForm, configItems=configItems)
Expand Down Expand Up @@ -102,9 +105,13 @@ def toggleUser(id):
def scope():
scope = ScopeItem.getScope()
scopeSize = current_app.ScopeManager.getScopeSize()
if scopeSize == 0: # if it's zero, let's update the app's scopemanager

# if it's zero, let's make sure the ScopeManager is up to date
if scopeSize == 0:
current_app.ScopeManager.update()
scopeSize = current_app.ScopeManager.getScopeSize() # if it's zero again that's fine, we just had to check
scopeSize = current_app.ScopeManager.getScopeSize()
# if it's zero again that's fine, we just had to check

newForm = NewScopeForm()
delForm = ScopeDeleteForm()
editForm = ScopeToggleForm()
Expand All @@ -121,8 +128,9 @@ def scope():
current_app.ScopeManager.update()
flash('%s added!' % newTarget.target, 'success')
return redirect(url_for('admin.scope'))
return render_template("admin/scope.html", scope=scope, scopeSize=scopeSize, delForm=delForm, editForm=editForm, newForm=newForm, importForm=importForm, \
addTagForm=addTagForm)
return render_template(
"admin/scope.html", scope=scope, scopeSize=scopeSize, delForm=delForm,
editForm=editForm, newForm=newForm, importForm=importForm, addTagForm=addTagForm)


@bp.route('/blacklist', methods=['GET', 'POST'])
Expand All @@ -135,6 +143,8 @@ def blacklist():
delForm = ScopeDeleteForm()
editForm = ScopeToggleForm()
importForm = ImportBlacklistForm()
addTagForm = TagScopeForm()
addTagForm.tagname.choices = [(row.name, row.name) for row in Tag.query.all()]
if newForm.validate_on_submit():
if '/' not in newForm.target.data:
newForm.target.data = newForm.target.data + '/32'
Expand All @@ -145,8 +155,9 @@ def blacklist():
current_app.ScopeManager.update()
flash('%s blacklisted!' % newTarget.target, 'success')
return redirect(url_for('admin.blacklist'))
return render_template("admin/blacklist.html", scope=scope, blacklistSize=blacklistSize, delForm=delForm, editForm=editForm, newForm=newForm, importForm=importForm)

return render_template(
"admin/blacklist.html", scope=scope, blacklistSize=blacklistSize, delForm=delForm,
editForm=editForm, newForm=newForm, importForm=importForm, addTagForm=addTagForm)


@bp.route('/import/<string:scopetype>', methods=['POST'])
Expand Down Expand Up @@ -189,6 +200,7 @@ def importScope(scopetype=''):
flash(error, 'danger')
return redirect(url_for('admin.%s' % scopetype))


@bp.route('/export/<string:scopetype>', methods=['GET'])
@isAuthenticated
@isAdmin
Expand All @@ -202,6 +214,7 @@ def exportScope(scopetype=''):
items = ScopeItem.query.filter_by(blacklist=exportBlacklist).all()
return Response('\n'.join(str(item.target) for item in items), mimetype='text/plain')


@bp.route('/scope/<int:id>/delete', methods=['POST'])
@isAuthenticated
@isAdmin
Expand Down Expand Up @@ -241,6 +254,7 @@ def toggleScopeItem(id):
flash("Form couldn't validate!", 'danger')
return redirect(request.referrer)


@bp.route('/scope/<int:id>/tag', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -258,6 +272,7 @@ def tagScopeItem(id):
flash("Form couldn't validate!", 'danger')
return redirect(request.referrer)


@bp.route('/scope/<int:id>/untag', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -275,13 +290,14 @@ def untagScopeItem(id):
flash("Form couldn't validate!", 'danger')
return redirect(request.referrer)


@bp.route('/services', methods=['GET', 'POST'])
@isAuthenticated
@isAdmin
def services():
uploadForm = ServicesUploadForm(prefix="upload-services")
addServiceForm = AddServiceForm(prefix="add-service")
addServiceForm.serviceProtocol.choices = [("tcp", "TCP"), ("udp","UDP")]
addServiceForm.serviceProtocol.choices = [("tcp", "TCP"), ("udp", "UDP")]
if uploadForm.uploadFile.data and uploadForm.validate_on_submit():
newServicesContent = uploadForm.serviceFile.data.read().decode("utf-8").rstrip('\r\n')
newServicesSha = hashlib.sha256(newServicesContent.encode()).hexdigest()
Expand Down Expand Up @@ -312,33 +328,37 @@ def services():
flash("New service %s on port %s has been added." % (newServiceName, newServicePort), "success")
return redirect(url_for('admin.services'))

return render_template(
0xdade marked this conversation as resolved.
Show resolved Hide resolved
'admin/services.html', uploadForm=uploadForm, addServiceForm=addServiceForm,
current_services=current_app.current_services, servlist=current_app.current_services['as_list'])

return render_template('admin/services.html', uploadForm=uploadForm, addServiceForm=addServiceForm, current_services=current_app.current_services, servlist=current_app.current_services['as_list'])

@bp.route('/services/export', methods=['GET'])
@isAuthenticated
@isAdmin
def exportServices():
return Response(str(current_app.current_services["services"]), mimetype='text/plain')


@bp.route('/agents', methods=['GET', 'POST'])
@isAuthenticated
@isAdmin
def agentConfig():
agentConfig = AgentConfig.query.get(1)
agentForm = AgentConfigForm(obj=agentConfig) # pass the model to the form to populate
agentForm = AgentConfigForm(obj=agentConfig) # pass the model to the form to populate
addScriptForm = AddScriptForm(prefix="add-script")
delScriptForm = DeleteForm(prefix="del-script")

if agentForm.validate_on_submit():
agentForm.populate_obj(agentConfig) # populate the object from the form data
agentForm.populate_obj(agentConfig) # populate the object from the form data
0xdade marked this conversation as resolved.
Show resolved Hide resolved
db.session.commit()
current_app.agentConfig = agentConfig.as_dict()


return render_template('admin/agents.html', agentForm=agentForm, scripts=current_app.agentScripts, \
return render_template(
'admin/agents.html', agentForm=agentForm, scripts=current_app.agentScripts,
addScriptForm=addScriptForm, delScriptForm=delScriptForm)


@bp.route('/agents/script/add', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -357,6 +377,7 @@ def addScript():
flash("%s couldn't be added to scripts" % addScriptForm.scriptName.data, "danger")
return redirect(request.referrer)


@bp.route('/agents/script/<string:name>/delete', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -375,6 +396,7 @@ def deleteScript(name):
flash("%s doesn't exist" % name, "danger")
return redirect(request.referrer)


@bp.route('/scans/delete/<scan_id>', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -383,7 +405,7 @@ def deleteScan(scan_id):

if delForm.validate_on_submit():
deleted = current_app.elastic.delete_scan(scan_id)
if deleted in [1,2]:
if deleted in [1, 2]:
flash("Successfully deleted scan %s." % scan_id, "success")
if request.referrer:
if scan_id in request.referrer:
Expand All @@ -400,6 +422,7 @@ def deleteScan(scan_id):
flash("Couldn't validate form!")
return redirect(request.referrer)


@bp.route('/hosts/delete/<ip>', methods=['POST'])
@isAuthenticated
@isAdmin
Expand All @@ -417,6 +440,7 @@ def deleteHost(ip):
flash("Couldn't validate form!")
return redirect(request.referrer)


@bp.route('/tags', methods=['GET', 'POST'])
@isAuthenticated
@isAdmin
Expand All @@ -425,7 +449,8 @@ def tags():

addForm = AddTagForm()
if addForm.validate_on_submit():
newTag = Tag(name=addForm.tagname.data.lower())
prepared_tag = addForm.tagname.data.strip()
newTag = Tag(name=prepared_tag)
db.session.add(newTag)
db.session.commit()
flash('Successfully added tag %s' % newTag.name, 'success')
Expand Down
2 changes: 1 addition & 1 deletion natlas-server/app/models.py
Expand Up @@ -121,7 +121,7 @@ def addTags(scopeitem, tags):
if existingTag:
scopeitem.addTag(existingTag)
else:
newTag = Tag(name=tag)
newTag = Tag(name=tag.strip())
db.session.add(newTag)
scopeitem.addTag(newTag)

Expand Down
36 changes: 36 additions & 0 deletions natlas-server/app/static/js/natlas-tagging.js
@@ -0,0 +1,36 @@
$('#tagmodal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var scopeid = button.data('scopeid') // Extract info from data-* attributes
var scopetarget = button.data('scopetarget') // Extract info from data-* attributes
var tagaction = button.data('action')
var tagstr = $('#scopeTags-'+scopeid).text().trim() // Trim whitespace in jinja formatting leaves whitespace
var tags = tagstr.split(', ')
var modal = $(this)
if (tagaction == 'add') {
modal.find('.modal-title').text('Add tag to ' + scopetarget)
modal.find('#tagScopeForm').attr('action', "/admin/scope/"+scopeid+"/tag")
modal.find('#tagScopeSubmit').text('Add Tag')
if (tagstr != ''){
tags.forEach(function(item) {
$("option[value=" + item.trim() + "]").attr('hidden', '') // hide this option because it's already added
$("option[value=" + item.trim() + "]").attr('disabled', '') // disable this option because it's hidden
0xdade marked this conversation as resolved.
Show resolved Hide resolved
});
}


} else {
modal.find('.modal-title').text('Remove tag from ' + scopetarget)
modal.find('#tagScopeForm').attr('action', "/admin/scope/"+scopeid+"/untag")
modal.find('#tagScopeSubmit').text('Remove Tag')
$("select[name='tagname']")[0].options.length = 0;
0xdade marked this conversation as resolved.
Show resolved Hide resolved

tags.forEach(function(item) {
$("#tagname").append(
$('<option>', {
value: item.trim(),
text: item.trim()
})
);
});
}
})
23 changes: 23 additions & 0 deletions natlas-server/app/templates/admin/_tagmodal.html
@@ -0,0 +1,23 @@
<div class="modal fade" tabindex="-1" role="dialog" id="tagmodal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Tag</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form method="POST" action="{{url_for('admin.scope')}}" id="tagScopeForm">
<div class="modal-body">
{{ addTagForm.hidden_tag() }}
{{ addTagForm.tagname(class="custom-select") }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" id="tagScopeSubmit" class="btn btn-primary">Add Tag</button>
</div>
</form>
</div>
</div>
</div>
<script src="/static/js/natlas-tagging.js"></script>
4 changes: 2 additions & 2 deletions natlas-server/app/templates/admin/blacklist.html
Expand Up @@ -35,7 +35,7 @@ <h3 class="mt-3">Manage Blacklist ({{ blacklistSize }} hosts)</h3>
<tr>
<th scope="row">{{ item.id }}</th>
<td>{{ item.target }}</td>
<td>{% for tag in item.tags %}{{ tag.name }}{% if not loop.last %}, {% endif %}{% endfor %}</td>
<td id="scopeTags-{{item.id}}">{% for tag in item.tags %}{{ tag.name }}{% if not loop.last %}, {% endif %}{% endfor %}</td>
<td style="text-align:center;">
{% include 'admin/_scope_menu.html' %}
</td>
Expand All @@ -57,5 +57,5 @@ <h3>Import Blacklist</h3>
</form>
</div>
</div>
{% include 'admin/_tagmodal.html' %}
{% endblock %}
67 changes: 2 additions & 65 deletions natlas-server/app/templates/admin/scope.html
Expand Up @@ -35,11 +35,7 @@ <h3 class="mt-3">Manage Scope ({{ scopeSize }} hosts)</h3>
<tr>
<th scope="row">{{ item.id }}</th>
<td>{{ item.target }}</td>
<td id="scopeTags-{{item.id}}">
{% for tag in item.tags %}
{{ tag.name }}{% if not loop.last %}, {% endif %}
{% endfor %}
</td>
<td id="scopeTags-{{item.id}}">{% for tag in item.tags %}{{ tag.name }}{% if not loop.last %}, {% endif %}{% endfor %}</td>
<td style="text-align:center;">
{% include 'admin/_scope_menu.html' %}
</td>
Expand All @@ -62,64 +58,5 @@ <h3>Import Scope</h3>
</div>
</div>

<div class="modal fade" tabindex="-1" role="dialog" id="tagmodal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Tag</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form method="POST" action="{{url_for('admin.scope')}}" id="tagScopeForm">
<div class="modal-body">
{{ addTagForm.hidden_tag() }}
{{ addTagForm.tagname(class="custom-select") }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" id="tagScopeSubmit" class="btn btn-primary">Add Tag</button>
</div>
</form>
</div>
</div>
</div>
<script>
$('#tagmodal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var scopeid = button.data('scopeid') // Extract info from data-* attributes
var scopetarget = button.data('scopetarget') // Extract info from data-* attributes
var tagaction = button.data('action')
var tagstr = $('#scopeTags-'+scopeid).text().replace(/\s+/g,'')
var tags = tagstr.split(',')
var modal = $(this)
if (tagaction == 'add') {
modal.find('.modal-title').text('Add tag to ' + scopetarget)
modal.find('#tagScopeForm').attr('action', "/admin/scope/"+scopeid+"/tag")
modal.find('#tagScopeSubmit').text('Add Tag')
if (tagstr != ''){
tags.forEach(function(item) {
$("option[value="+item+"]").attr('hidden', '')
$("option[value="+item+"]").attr('disabled', '')
});
}


} else {
modal.find('.modal-title').text('Remove tag from ' + scopetarget)
modal.find('#tagScopeForm').attr('action', "/admin/scope/"+scopeid+"/untag")
modal.find('#tagScopeSubmit').text('Remove Tag')
$("select[name='tagname']")[0].options.length = 0;

tags.forEach(function(item) {
$("#tagname").append(
$('<option>', {
value: item,
text: item
})
);
});
}
})
</script>
{% include 'admin/_tagmodal.html' %}
{% endblock %}