applications secure by default

100
Platinum Sponsors: #DevoxxPL Applications secure by default Sławomir Jasek

Upload: slawomir-jasek

Post on 17-Jan-2017

146 views

Category:

Software


0 download

TRANSCRIPT

Platinum Sponsors:

#DevoxxPL

Applications secure by default

Sławomir Jasek

Pentester / security consultant.

Assessments and consultancy regarding

security of various applications - web,

mobile, embedded, ...

Since 2003 / over 400 systems and

applications

Sławomir Jasek

Code insecure by default

Blacklisting vs whitelisting

Features vs security

Access control

Beware the "silver bullets"

Fight back!

Devops

The Takeaway

Agenda

INSECURE BY DEFAULT

$url =

'https://api.twitter.com/1/statuses/public_timeline.json';

$result = file_get_contents($url);

Is there anything wrong?

The default setting does not verify hostname => Man in the Middle

$url = 'https://api.twitter.com/1/statuses/public_timeline.json';

$contextOptions = array(

'ssl' => array(

'verify_peer' => true,

'cafile' => '/etc/ssl/certs/ca-certificates.crt',

'verify_depth' => 5,

'CN_match' => 'api.twitter.com',

'disable_compression' => true,

'SNI_enabled' => true,

'ciphers' => 'ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4'

)

);

$sslContext = stream_context_create($contextOptions);

$result = file_get_contents($url, NULL, $sslContext);

The proper way

http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-%28HTTPS-SSL-and-TLS%29.html

Defaults to false!

file_get_contents(https language:php

file_get_contents verify_peer

Only 1 programmer in 51 uses verify_peer options.

Often to explicitly disable it ;)

The default value changed only recently in PHP 5.6.0.

But there is hope...

All the previous versions susceptible to Man-In-The-Middle attacks.

$url =

'https://api.twitter.com/1/statuses/public_timeline.json';

$req = curl_init($url);

curl_setopt($req, CURLOPT_RETURNTRANSFER, TRUE);

$result = curl_exec($req);

Curl - secure by default

// Open SSLSocket directly

SocketFactory sf = SSLSocketFactory.getDefault();

SSLSocket socket = (SSLSocket) sf.createSocket("mail.google.com", 443);

SSLSession s = socket.getSession();

// ... use socket ...

socket.close();

Java: SSL SocketFactory

// Open SSLSocket directly

SocketFactory sf = SSLSocketFactory.getDefault();

SSLSocket socket = (SSLSocket) sf.createSocket("mail.google.com", 443);

SSLSession s = socket.getSession();

// Verify that the certicate hostname is for mail.google.com

HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();

if (!hv.verify("mail.google.com", s)) {

throw new SSLHandshakeException("Expected mail.google.com, "

"found " + s.getPeerPrincipal());

}

// ... use socket ...

socket.close();

https://developer.android.com/training/articles/security-ssl.html#WarningsSslSocket

SSL SocketFactory

And the docs do not help

https://developer.android.com/training/articles/security-ssl.html#WarningsSslSocket

Pentester’s experience: all tested Android apps using SSLSocket were vulnerable.

Despite the bold warnings and proper example code...

URL url = new URL("https://mail.google.com");

URLConnection urlConnection = url.openConnection();

InputStream in = urlConnection.getInputStream();

copyInputStreamToOutputStream(in, System.out);

You need to explicitly disable verification.

Pentester’s experience: only a few tested Android apps using urlConnection were deliberately broken.

HTTPS – the proper way

BLACKLISTING

Attack scenario:

http://localhost/foo/bar.action?<script>alert(1)</script>

Lack of proper output encoding.

Intruder runs hostile javascript in a victim’s browser (aka „Cross Site Scripting”).

Struts 2 – XSS vulnerability

--- struts2/trunk/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java 2008/01/24 07:37:32 614813

+++ struts2/trunk/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java 2008/01/24 07:39:45 614814

@@ -174,10 +174,14 @@

buildParametersString(params, link, "&");

}

- String result;

+ String result = link.toString();

+

+ if (result.indexOf("<script>") >= 0){

+ result = result.replaceAll("<script>", "script");

+ }

Fix - blacklisting

Attack 1:

/myAction.action?param"><sCript>alert('XSS');</sCript>=1

This is very similiar to the vulnerability in Security Bulletin S2-002; however, the implemented fix for S2-002 only checks for "<script>", not "<sCript>".

Attack 2:

/myAction.action?param"onMouseOver%3D"javascript:alert('XSS');">=1

Simply checking for <script> isn't sufficient because certain attributes can be injected to execute javascript. In attack 2, the user simply has to hover over the link with their mouse and arbitrary javascript will be executed.

https://issues.apache.org/jira/browse/WW-3410

2 years later...

-builder.append(name)

+builder.append(translateAndEncode(name))

That was 19 characters - exactly 4.78 times less than 91

characters used in first, unsuccessful „blacklist” fix.

Final fix

We found an XSS vulnerability, as usually recommended

to properly encode relevant characters in the output

context.

Retest #1: <script> does not work, but <Script> does ;)

Retest #2: <Script> nor <sCript> does not work. But onclick does.

Retest #3: onclick does not work, but onmouseover does.

Retest #4: onmouseover fixed, but onmousedown not ;)

Retest #5: ...

From the pentester's diary

+------------------------+

| XSS_PAYLOAD |

+------------------------+

| onclick= |

| ondblclick= |

| onmousedown= |

| onmousemove= |

| onmouseover= |

| onmouseout= |

| onmouseup= |

| onkeydown= |

| onkeypress= |

| onkeyup= |

| onabort= |

| onerror= |

| onload= |

| onresize= |

Finally, we broke into database via sql-injection

| onscroll= |

| onunload= |

| onblur= |

| onchange= |

| onfocus= |

| onreset= |

| onselect= |

| onsubmit= |

| onevent= |

| <script |

| script> |

| <svg |

| svg> |

| javascript: |

| <iframe | | iframe> | | <form | | form> | | <input | | ''iframe'' | | "iframe" | | document.createelement | | string.fromcharcode( | | <img/src | | submit() | | document.location. | | alert( | | <img | | <vbscript | ...

www.example.com/?file=../etc/passwd

Fix: remove ../

www.example.com/?file=....//etc/passwd

www.example.com/?file=....//etc/passwd

www.example.com/?file=../etc/passwd

Proper way: whitelist of allowed characters.

Path traversal

FEATURES VS SECURITY

Define user

# fields: [:id, :first, :last, :email, :admin]

class User < ActiveRecord::Base

End

RoR – user edit form

User edit form

user = User.find(params[:id])

user.update_attributes(params[:user])

PUT

http://app.com/users/66?user[first]=Slawomir

&user[last]=Jasek&user[email]=slawomir.jasek

@securing.pl

RoR – user edit form

PUT

http://app.com/users/66?user[first]=Slawomir

&user[last]=Jasek&user[email]=slawomir.jasek

@securing.pl&user[admin]=true

RoR – mass assignment

You were supposed to manually add whitelisted:

class User < ActiveRecord::Base

attr_accessible :first, :last, :email

end

or blacklisted parameters:

class User < ActiveRecord::Base

attr_protected :admin

end

RoR – mass assignment (2012)

GitHub PWND

http://www.h-online.com/security/news/item/GitHub-security-incident-highlights-Ruby-on-Rails-problem-1463207.html

Change default value of global config parameter turning

the mass assignment off:

# Enforce whitelist mode for mass assignment.

# This will create an empty whitelist of attributes available for mass-

assignment for all models

# in your app. As such, your models will need to explicitly whitelist or

blacklist accessible

# parameters by using an attr_accessible or attr_protected declaration.

<%= comment_if :skip_active_record %>

config.active_record.whitelist_attributes = true

Fix - evolution

config.active_record.mass_assignment_sanitizer

It will raise an

ActiveModel::MassAssignmentSecurity::Error

any time your application attempts to mass-assign something it shouldn't.

RoR 3.2: Mass assignment sanitizer

Before:

<%=HTMLEncoder.encode(((Person)person).getAd

dress().getStreet())%>

After (EL):

<c:out value="person.address.street"/>

Expression language – starring major frameworks

DEMO

- The security impact

Major frameworks: Spring, JBoss SEAM, Struts...

Easy to detect, automatic tools to exploit remotely into shell.

The "no man's land".

(as I have pointed out in 2012)

http://prezi.com/awm8psp-i1ok/no-mans-land

Expression Language flaws

https://play.google.com/store/apps/details?id=com.cleanmaster.security.struts2

2003: parameter names like: @System@exit(1)

"Patrick says he has fixed it" ;)

2008.06: the # can be encoded in \u0023

('\u0023' + 'session[\'user\'])(unused)=0wn3d

Released Xwork 2.0.5 – blacklisted the attack

2008.10: removed space characters and the exploit still

works ;)

('\u0023'+'session[\'user\'])(unused)=0wn3d

The fix - features vs security

2010: You can access the context and turn the settings on:

http://mydomain/MyStruts.action?('\u0023_memberAccess[\'allowStatic

MethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAcc

essor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20

java.lang.Boolean("false")))&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u

[email protected]@getRuntime()))=1

Fix: whitelist allowed chars in parameter names

2011: User input is evaluated as an OGNL expression when there's a

conversion error.

2011: The problem concerns not only parameters, but also cookie

values

The fix – continued...

2012: fix based on whitelisting acceptable parameter names closed the vulnerability only partially. Still possible RCE with slightly modified attack syntax.

Fix: deny evaluation in parameter names.

2013: The second evaluation happens when redirect result reads it from the stack and uses the previously injected code as redirect parameter.

I won't reveal all the following episodes, I encourage you to read on:

http://struts.apache.org/docs/security-bulletins.html

There's a lot of action! Struts.action.

The fix – continued

data=%3C%3Fxml+version%3D%221.0%22%3F%3E%0A%3Cuser%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Cfirstname%3EJan%3C%2Ffirstname%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Clastname%3EKowalski%3C%2Flastname%3E%0A%3C%2Fuser%3E

HTML decoded:

<?xml version="1.0"?>

<user>

<firstname>Jan</firstname>

<lastname>Kowalski</lastname>

</user>

XML parsing

<?xml version="1.0"?>

<!DOCTYPE lolz [

<!ENTITY lol "lol">

<!ELEMENT lolz (#PCDATA)>

]>

<lolz>&lol;</lolz>

<lolz>lol</lolz>

XML parsing: DOCTYPE

<?xml version="1.0"?>

<!DOCTYPE lolz [

<!ENTITY lol "lol">

<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">

<!ELEMENT lolz (#PCDATA)>

]>

<lolz>&lol1;</lolz>

<lolz>lollollollollollollollollollol</lolz>

XML parsing: DOCTYPE

<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz> <user> <firstname>Jan</firstname> <lastname>Kowalski</lastname> </user>

"The Man Who Laughs"

http://en.wikipedia.org/wiki/Billion_laughs

ROTFL TO DEATH!!!

<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>

<foo>&xxe;</foo>

As seen in Google, Facebook, Ebay and about 80%

of tested applications processing user input as XML.

It may be even worse

FB XXE

Technology Default DTD processing value

.NET 4 settings.DtdProcessing = DtdProcessing.Prohibit;

.NET 3.5 ProhibitDtd in XmlReaderSettings is true, but ProhibitDtd in XmlTextReader is false

LibXML2 (C++ ) starting with libxml2 version 2.9 (2012), XXE has been disabled by default

NSXMLDocument (iOS)

iOS5 and later: Only entities that don't require network access are loaded.

iOS4 and earlier: All external entities are loaded by default.

Xerces 2 disallow-doctype-decl=false

Xerces 1 external-general-entities=true

PHP Have to manually disable: libxml_disable_entity_loader(true);

Default DTD processing in various parsers

ACCESS CONTROL

Access control: typical scenario

Student tries to invoke administrative functions

GET /course/quiz/solutions

GET /admin/course/cancel

Student tries to access restricted data

GET /course/view/42

Student tries to alter his account rights.

POST /user/edit

roles=[student,admin]

Access control: typical attack

<security:intercept-url pattern="/user/add"

access="hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')" />

<security:intercept-url pattern="/user/view"

access="hasRole('ROLE_ADMIN')

or hasRole('ROLE_MANAGER')

or hasRole('ROLE_PRINCIPAL')

or hasRole('ROLE_TEACHER')

or hasRole('ROLE_STUDENT')" />

Approach 1: Spring Security

It works for simple apps, with unsophisticated role policies (e.g. separated admin interface).

Will not work for:

POST /user/edit HTTP/1.1

task=MODIFY_RIGHTS&id=34

Has concept of „roles”, but out of the box does not have concept of „permissions”. Spring ACL on the other hand is too complex.

Does not help a lot with access to specific instance (e.g. other user’s data)

Spring Security

Complex hard-coded checks in application code, needed to be manually loaded to every endpoint:

If (( user.isRole('ROLE_ADMIN') ||

user.isRole('ROLE_MANAGER') ||

user.isRole('ROLE_PRINCIPAL') ) ||

( user.isRole('ROLE_TEACHER') &&

user.isTeacher(course) ) ||

( user.isRole('ROLE_STUDENT') &&

(user.isStudent(course) )

...and you will probably end-up with:

One simple "if" statement, permissions separated from roles.

if ( currentUser.isPermitted("users:add") ) {

//add an user

}

int courseId=request.getInt("course")

if ( currentUser.isPermitted("courses:view:"+courseId) ) {

//show contents of course

}

Apache Shiro – permission based access control

Real story: account history – select your account

The REST API request

GET /services/history/account/85101022350445200448009906 HTTP/1.1

SA-DeviceId: 940109f08ba56a89

SA-SessionId: 826175

Accept: application/json

Host: acc

Connection: Keep-Alive

User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

The REST API request

GET /services/history/account/45101022350445200448005388 HTTP/1.1

SA-DeviceId: 940109f08ba56a89

SA-SessionId: 826175

Accept: application/json

Host: acc

Connection: Keep-Alive

User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

Change the acc number -> get other user’s data

John:

<select name="account">

<option value=0 >85101022350445200448009906</option>

<option value=1 >34101022350445200448009905</option>

<option value=2 >41101022350445200448009904</option>

</select>

Mary:

<select name="account">

<option value=0 >45101022350445200448005388</option>

<option value=1 >31101022350445200448005390</option>

</select>

The better way?

"Local" ID mapped server-side into real values

The better way?

SA-DeviceId: d4c79a0fd994b1f3

SA-SessionId: 850073

GET /services/history/account/1 HTTP/1.1

SA-DeviceId: 940109f08ba56a89

SA-SessionId: 826175

Accept: application/json

Host: acc

Connection: Keep-Alive

User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)

It is(?) by design not possible to attack other user's data.

Would be great if not...

John: GET /services/history/account/2 HTTP/1.1

SA-DeviceId: 940109f08ba56a89

SA-SessionId: 826175

Accept: application/json

Host: acc

Connection: Keep-Alive

API just works as a proxy to backend system. Default session mechanism from backend – just incrementing IDs ;)

Mary: GET /services/history/account/2 HTTP/1.1

SA-DeviceId: d4c79a0fd994b1f3

SA-SessionId: 826179

Accept: application/json

Host: acc

Connection: Keep-Alive Trivial to guess other user's sessionId

Automatically encrypts paths with individual, session-based and unique key:

www.app.com/admin/user/edit

www.app.com/?x=XSn4MUyv6Uke22d9vEuGgR8yZa5-TkeuxlXeeVypcehJ8HQgNbj(...)

Apache Wicket

The browser works on rendered GUI elements, POSTs to the server event-driven actions (e.g. mouse clicks in certain location).

It is by design not possible to invoke actions that are not in GUI.

POST /dashboard/UIDL/?v-uiId=0 HTTP/1.1

Host: demo.vaadin.com

{"csrfToken":"981b1cd6-66df-481c-9d6e-6c293eb70ea3","rpc":[["283","v","v",["positionx",["i","440"]]],["283","v","v",["positiony",["i","139"]]],["309","com.vaadin.shared.ui.button.ButtonServerRpc","click",[{"altKey":false,"relativeX":"42","relativeY":"23","ctrlKey":false,"button":"LEFT","shiftKey":false,"clientX":"1109","clientY":"598","metaKey":false,"type":"1"}]]],"syncId":14}

Vaadin

BEWARE

There's no silver bullet!

Hadi Hariri keynote on Monday

Automagic output encoding by framework

A framework automatically encodes special chars into

HTML:

<bean:write name="transferFormId" property="trn_recipient"/>

ATTACK: trn_recipient="<script>alert('xss')</script>

<input type="text" name="trn_recipient"

value="&quot;&lt;script&gt;alert('xss')&lt;/script&gt;"

Beware the security mechanism use cases

But unfortunatelly that does not help when you put a value from end-user directly into javascript context:

<script> var split='<bean:write name="transferFormId" property="trn_recipient">'; splitRecipient(split); </script>

ATTACK: trn_recipient=';alert('xss');-- <script> var split='';alert('xss');--

Encode special chars properly in context!

• HTML element

• HTML atribute

• JavaScript

• JSON

• CSS / style

• URL

Encode properly

Prepared statement / call

String sql = "select * from users where

firstname=? and lastname=?";

query = conn.prepareStatement(sql);

firstname = request.getParameter("first");

lastname = request.getParameter("last");

query.setString(1, firstname);

query.setString(2, lastname);

result = query.executeQuery();

String sql = "{call

USERS.search(" + "?" + ", ?)}";

call = conn.prepareCall(sql);

firstname = request.getParameter("first");

lastname = request.getParameter("last");

call.setString(1, firstname);

call.setString(2, lastname);

call.execute();

prepared statement prepared call

Called stored procedure

PROCEDURE search(

p_firstname IN T_STRING,

p_lastname IN T_STRING,

) IS

(...)

v_sql_select := ' SELECT distinct a.USER_ID';

v_sql_from := ' FROM APP_WEB.USERS a ';

v_sql_where := ' WHERE a.USER_ID is not null ';

IF p_firstname is not null THEN

v_sql_where := v_sql_where || ' and lower(trim(a.FIRSTNAME)) =

lower(trim(' || P_FIRSTNAME || ')) ';

END IF;

SQL injection inside stored procedure

PROCEDURE search(

p_firstname IN T_STRING,

p_lastname IN T_STRING,

) IS

(...)

v_sql_select := ' SELECT distinct a.USER_ID';

v_sql_from := ' FROM APP_WEB.USERS a ';

v_sql_where := ' WHERE a.USER_ID is not null ';

IF p_firstname is not null THEN

v_sql_where := v_sql_where || ' and lower(trim(a.FIRSTNAME)) =

lower(trim('|| 'adam')) union select version,'x' from v$instance-- || ')) ';

END IF;

NoSQL. There is no sql injection.

There is nosql injection!

Instead of

' OR 1=1 --

try

a'; return 1=1; var dummy='a

NoSQL

Change SMS authorization phone number in internet banking application

Application logic flaws

What could possibly go wrong?

Change SMS authorization phone number in internet banking application

The scenario missed in functional tests

Change SMS authorization phone number in internet banking application

The evil wins

The application did verify only the SMS code from the new phone. And intruder with access to user session can take over the authorization.

FIGHT BACK!

- Intrusion detection and prevention

• Input validation server-side when client-side validation exists

• Non-user editable parameters/values (hidden fields, checkboxes, radio buttons, select lists)

• Forced browsing to common attack entry points or honeypot URL (e.g. in robots.txt)

• Obvious sqli, xss inj attacks

• Workflow sequence abuse

Intrusion detection – level basic

http://www.slideshare.net/JimManico/top-ten-defenses-v10 slide 60

One of the most annoying experiences during test was

automatic logout on every test-case in application that required manual interaction to authenticate.

Active intrusion prevention

OWASP AppSensor

Conceptual framework and methodology to implement intrusion detection and

automated response into applications.

https://www.owasp.org/index.php/OWASP_AppSensor_Project

OWASP mod_security core ruleset

An easily "pluggable" set of generic attack detection rules that

provide a base level of protection for any web application.

https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project

Basic tools

DEVOPS

- Default infrastructure

Default error handling

Reveals information on used components, helps to attack known vulnerabilities

Trading application – binary protocol

Trading application – binary protocol

Trading application – binary protocol

And what if we...

And how about...

<soapenv:Body> <registerUserResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<registerUserReturn xsi:type="xsd:string">

&lt;error code=&quot;266&quot; &gt;Incorrect login&lt;/error&gt;

</registerUserReturn></registerUserResponse></soapenv:Body>

• Incorrect password

• Incorrect first name

• Group with name null doesn't exist

• Group with name admin doesn't exist

• Group with name Administrator doesn't exist

• And how about „root”?

RegisterUser

Game Over

<soapenv:Body>

<registerUserResponse

soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/

encoding/">

<registerUserReturn xsi:type="xsd:string">

User was registered sucessfully with id=5392745

Access to system with administartor rights. Possible to manage accounts of all other users.

Architecture

Default HTTP error response

Reveals used version

Known vulnerabilities based on version

Apache Tomcat < 6.0.20

<role rolename="tomcat"/>

<role rolename="role1"/>

<user username="tomcat" password="tomcat" roles="tomcat"/>

<user username="both" password="tomcat" roles="tomcat,role1"/>

<user username="role1" password="tomcat" roles="role1"/>

tomcat-users.xml

Apache Tomcat Manager

Tomcat worm using weak passwords

http://www.symantec.com/connect/blogs/all-your-tomcat-are-belong-bad-guys

tryLogins = { "admin:admin", "tomcat:tomcat", "admin:", "tomcat:", "root:root", "manager:manager", "tomcat:admin", "admin:password"};

OWASP dependency check / dependency track

Automatically checks for known vulnerabilities in used components

https://www.owasp.org/index.php/OWASP_Dependency_Track

THE TAKEAWAY

• Use secure design architecture

• Least privilege principle (default: deny)

• Code that enforces good practices

• Leverage existing security mechanisms, but be aware of their shortcomings and secure use scenario.

• Secure configuration

• Keep the components up to date

• Change default credentials

• Harden the configuration

• Leverage additional layers of protection (IDS, WAF)

Key takeaways

Our presentations (including this one), resources

www.securing.pl/en/resources/

Free security consultancy service:

www.securing.pl/konsultacje

See also

And for the Happy(?)-End – the pentester’s view

Features at low cost compromising on security is just obscene ;) Let’s do it better!

Thank you,

looking forward to contact!

[email protected]

MORE THAN SECURITY TESTING

Free security consultancy service:

www.securing.pl/konsultacje