Skip to content

Instantly share code, notes, and snippets.

@maretekent
Created March 28, 2018 18:38
Show Gist options
  • Save maretekent/be7fe1b99fe024ebf74e47d24b1baa75 to your computer and use it in GitHub Desktop.
Save maretekent/be7fe1b99fe024ebf74e47d24b1baa75 to your computer and use it in GitHub Desktop.
basic django security key elements worthy noting
XXE injection:
To use these parsers safely, you have to explicitly disable referencing of external entities in the
SAX parser implementation you use.
problem:
from django.http import HttpResponse
from lxml import etree
parser = etree.XMLParser(resolve_entities=True)
try:
document = etree.fromstring(content, parser)
except etree.XMLSyntaxError:
return None
solution:
set parser = etree.XMLParser(resolve_entities=False) -- set it to False
disallowing inline DTD is a good defense against this type of attack,
but implementing this is specific to the XML parsing engine being used.
Command Injection:
Should any non alphanumeric characters be encountered, the re.match() method will automatically escape the input,
preventing malicious control shell characters from being passed to the statlab program.
Although the proposed fix is sufficient to remediate our vulnerable example,
the overall logic and security design for os.popen() method can be significantly
improved by not accepting user supplied myUid value through the request.GET['username'] parameter.
import os
from django.http import HttpResponse
import re
def executeCommand(request):
myUid = request.GET['username']
matchResult = re.match(r"[0-9A-Za-z]+$", myUid)
if not matchResult:
return HttpResponse("Inva
out = os.popen("/usr/bin/statlab " + "-" + myUid).read()
return HttpResponse(out)Copy-paste code here to remove the line numbers.
Session Fixation:
1. Ensure that only server generated session values are accepted by the application.
2. Upon a successful login, invalidate the original session value, and re-issue a new session value.
3. Prevent the application from accepting session values via GET or POST requests and
instead store session values within HTTP Cookies only.
def authenticate(request, username, password):
user = verify_uname_password(username, password)
if user and user.is_active:
request.session.flush()
request.session.cycle_key()
@maretekent
Copy link
Author

Reflected XSS:
%3Cscript%3Ealert('You got hacked')%3C%2Fscript%3E

The most effective method to protect against XSS attacks is by escaping all
unstrusted user input. In our example removing the safe keyword,
when displaying user-controlled input will ensure that all user supplied
input is automatically escaped and encoded, including < , > , " , ' and &
thereby preventing injection of potentially malicious HTML code.

@maretekent
Copy link
Author

maretekent commented Mar 28, 2018

Persistent Cross Site Scripting (XSS):
To help defend against Stored Cross Site Scripting (XSS) attacks
it is important to ensure that user-supplied data is output encoded
before being served by the application to other users.

By correctly escaping the data, when it is served to the user for
display in their browser, the browser does not interpret it as code and
instead interprets it as data, thus ensuring it does not get executed.

In essence output encoding effectively works by escaping user-supplied
data immediately before it is served to users of the application.

The most effective method to protect against XSS attacks is by escaping all
unstrusted user input. In our example removing the safe keyword, when displaying
user-controlled input will ensure that all user supplied input is automatically escaped
and encoded, including < , > , " , ' and & thereby preventing injection of potentially malicious HTML code.

@maretekent
Copy link
Author

maretekent commented Mar 28, 2018

DOM XSS:

<script> var name = document.location.hash.split('#')[1]; //https://tradenews.codebashing.com/guests/landing#guest document.write("Hello " + name + "! Please login or signup to access news stories"); </script>

https://tradenews.codebashing.com/guests/landing#<script>window.location = 'https://fake-tradenews.codebashing.com';</script>

DOM XSS, the attack is injected into the Browser DOM, this adds additional complexity and makes it very difficult to prevent and highly context specific, because an attacker can inject HTML, HTML Attributes, CSS as well as URLs. As a general set of principles the application should first HTML encode and then Javascript encode any user supplied data that is returned to the client.

Due to the very large attack surface developers are strongly encouraged to review areas of code that are potentially susceptible to DOM XSS, including but not limited:

window.name document.referrer document.URL document.documentURI location location.href location.search location.hash eval setTimeout setInterval document.write document.writeIn innerHTML outerHTML

example fix:
if (name.match(/^[a-zA-Z0-9]*$/))
{
document.write("Hello " + name + "! Please login or signup to access news stories");
}
else
{
window.alert("Security error");
}

@maretekent
Copy link
Author

Directory (Path) Traversal:
https://traderesearch.codebashing.com/trade_news?file=../etc/passwd
#!/usr/bin/python

-- coding: utf-8 --

if os.path.realpath('/tmp/' + filename).startswith('/tmp/'):
file_ = open(os.path.join('/tmp/', filename))
content = file_.read()
else:
return HttpResponse('Security Error')

@maretekent
Copy link
Author

Left Over Debug Code:
if isDebug and isDebug == '1':
request.session['username'] = 'admin'
request.session['isAdmin'] = 'True'
isAuthenticated = True

@maretekent
Copy link
Author

Authentication Credentials In URL:
Transmitting login credentials via GET requests is never a good idea,
because URLs are inevitably stored in multiple places that an application
developer has no control over. When the Login Credentials are present within
the URL, and that URL is stored, it increases the likelihood of inadvertent login
credential exposure. For instance, URL Sare commonly stored in:

  1. Browser history
  2. Browser bookmarks
  3. Referrer headers when resources are linked
  4. Upstream proxy logs
  5. Web application logs
    protect sensitive user-supplied data, the application should only accept communication from a logged-in user over HTTPS, and never over HTTP.

@maretekent
Copy link
Author

Session Exposure within URL:
logging onto the application, her unique Session Identifier gets
automatically logged onto the backend webserver logfile, thereby allowing
other users to access her session information.

Another reason to not trasmit Session Identifiers via GET request, only via
POST is that a user may inadvertently share their own session with others
when copy-pasting web links to the application for instance.

@maretekent
Copy link
Author

User Enumeration:
When it is possible to determine whether a user name is valid or not, it is known as a Username Enumeration vulnerability.

NB: 'Username Enumeration' can exist in other areas of an application, not just within a 'Forgotten Password' function.

@maretekent
Copy link
Author

Horizontal Privilege Escalation:
Unfortunately, the SQL statement used to fetch Bob's profile does not
perform any authorization / user context awareness checks and further
allows direct referencing of objects via the uid parameter.

This means that a malicious user can simply manipulate the uid variable to
access other objects (user profiles) within the application without proper authorization.

This is also known as an "Insecure Direct Object Reference" (IDOR) attack.

@maretekent
Copy link
Author

Horizontal Privilege Escalation:
cur_username = request.session.get("username", None)
if not cur_username:
return HttpResponse("user not authenticated")
cursor = connection.cursor()
cursor.execute("select name, email, phone, department from users where user_id = %s and username = %s", [uid, cur_username])
row = cursor.fetchone()

@maretekent
Copy link
Author

Vertical Privilege escalation:
In our updated code fix, we check if the User model has the is_superuser
field set to true, which indicates that the user ( Bob ) has passed both
authentication and authorization checks to access site

@maretekent
Copy link
Author

Cross Site Request Forgery (POST):

We are experiencing some technical problems. Our website is expected to be back online shortly. We apologize for the inconvenience.

<iframe style="display:none" name="csrf-frame"></iframe> <script>document.getElementById("csrf-form").submit()</script>

@maretekent
Copy link
Author

ensure always the post form has crsf-token ---
This technique of programmatically inserting random token values in every web page is known as the synchronizer token pattern

The pattern implements the generating of random "challenge" tokens that are associated with the user's current session, which are then verified for the existence and correctness of this token on the server side.

@maretekent
Copy link
Author

Cross Site Request Forgery (GET):
It is bad practice to implement Update, Create and Delete operations that
rely on user supplied input via HTTP GET requests, this is an example of misuse of HTTP Verbs.

@maretekent
Copy link
Author

maretekent commented Mar 31, 2018

Click Jacking:
To defend against Click Jacking attacks the web server should be
configured to send X-Frame-Options in the response headers.

Configuring the X-Frame-Options to either DENY, SAMEORIGIN, or
ALLOW-FROM will prevent malicious websites from embedding your application's content.

I.e. it will prevent the browser from loading your application content within or <iframe> tags of other websites.

In Django, this can be configured by specifying the clickjacking.XFrameOptionsMiddleware middleware to the following directive:

X_FRAME_OPTIONS = 'DENY'
However, a more scalable approach would be to deploy HTTP headers globally,
at the web server layer. Let's see how we can configure Apache to set the X-Frame-Options header across all pages.

@maretekent
Copy link
Author

# Prevent Clickjacking using X-Frame-Options header Header set X-Frame-Options "deny" # Prevent Clickjacking using Content Security Policy (Not supported by all major browsers yet) Header set Content-Security-Policy: frame-options 'deny'; # Chrome / Firefox Header set X-Content-Security-Policy: frame-options 'deny'; # Internet Explorer

@maretekent
Copy link
Author

Insecure URL Redirect:
extra validation very important.
if url and url == "https://sso.codebashing.com":

@maretekent
Copy link
Author

Insecure Tls Validation:
As with any user supplied input, it is important to ensure there is a context specific input validation strategy in place. For example, consider the case of a TLS/SSL man-in-the-middle attack, that could abuse the incorrectly defined certificate validation logic.

@maretekent
Copy link
Author

Insecure Object Deserialization:
Most programming languages including Python provide built-in ways for developers to serialize objects to a byte stream and then re-construct those objects using the deserialization process.

Vulnerabilities arise when developers try to construct an object from an untrusted serialization stream, and they assume that this stream can always be trusted.

If the stream was corrupted, tampered with or replaced prior to deserialization, the deserialized objects may have an unexpected or illegal state.

One of the worst consequences of insecure object deserialization is Remote Code Execution.

If an attacker can make a remote server execute an arbitrary command - they could then:

Upload and execute a backdoor.
Pivot, and attack other systems on the same network.
Use the server as a part of a botnet.
Use the server as a cryptocurrency miner.
In this lesson, the deserialization vulnerability in the Python pickle module will be explored. This module implements an algorithm for serializing and deserializing a Python object structure

@maretekent
Copy link
Author

screen shot 2018-03-31 at 23 47 27

@maretekent
Copy link
Author

The json.loads() method then saves the extracted JSON to the exceptionRecordJson variable. And after that its value is passed to the ExceptionRecord constructor class that records the parced error message to the server log.

When the parsed error message is processed, the self.wfile.write() method sends the response in the form of JSON back to the client .

@maretekent
Copy link
Author

content_length = self.headers.getheaders('content-length')
length = int(content_length[0]) if content_length else 0

pickledError = self.rfile.read(length)

exceptionRecord = cPickle.loads(base64.b64decode(pickledError))

self._set_headers()
jsonRecordError = self.rfile.read(length)
exceptionRecordJson = json.loads(jsonRecordError)
try:
exceptionRecord = ExceptionRecord(exceptionRecordJson["version"], exceptionRecordJson["log"], exceptionRecordJson["userID"])
saveError(exceptionRecord)
self._set_headers()
self.wfile.write(createJSONSuccess(exceptionRecord));
except (ValueError, TypeError, NameError) as e:
log_error(e, exceptionRecord)
self._set_error_headers()
self.wfile.write(createJSONError(e,exceptionRecord));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment