Taking on the King:Killing Injection Vulnerabilities
Taking on the King:Killing Injection Vulnerabilities
Justin Collins@presidentbeef
AppSec California 2018
Injection in the OWASP Top 10
2004 2009 2010 2013 2017
Injection A6 A2 A1 A1 A1
Cross-Site Scripting A4 A1 A2 A3 A7
Injection in the Wild
“...the average payout for SQLi was the highest at $1,058”
BugCrowd State of Bug Bounty Report 2017
What is an Injection Vulnerability?
DATA interpreted as CODEQuery Parameters
Form ValuesHeader ValuesUploaded Files
Database Values...
SQLHTMLJavaScriptBash ScriptXML Entities...
What is an Injection Vulnerability?
Developer Code Attacker Code
Interpreter
Developer Code
Database DriverBrowserWeb ServerMail ServerShellTemplating LibraryXML ParserLDAP Parsereval()...
SQL Injection Example
query = "SELECT * FROM users WHERE email='" + email + "'"
db.execute(query)
Expected to be DATA
SQL Injection Example
query = "SELECT * FROM users WHERE email='" + email + "'"
db.execute(query)
Expected to be DATALooks like DATA,but is CODE
SQL Injection Example
email = request.params["email"]
query = "SELECT * FROM users WHERE email='" + email + "'"
db.execute(query)
User Input
SQL Injection Example
email = "' OR 1=1;--"
query = "SELECT * FROM users WHERE email='" + email + "'"
db.execute(query)
Attacker Input
SQL Injection Example
email = "' OR 1=1;--"
query = "SELECT * FROM users WHERE email='' OR 1=1;--'"
db.execute(query)
DATA now interpreted as CODE
Some SQL Injection
Python
query = "SELECT * FROM users WHERE email = '%s'" % (request.POST.get('email'))
cursor.execute(query)
Ruby / ActiveRecord
query = "SELECT * FROM users WHERE email = '#{params[:email]}'"ActiveRecord::Base.connection.execute(query)
Java
String user = request.getParameter("email");Statement st = conn.createStatement();String query = "SELECT * FROM user where userId='" + email + "'";st.executeQuery(query)
Go
db.Query("SELECT *FROM users WHERE email='" + req.FormValue("email") + "'")
Some Command Injection
Python
cmd = "rm -rf /tmp/%s" % request.POST.get("username")
os.system(cmd)
Ruby
`rm -rf #{params[:username]}`
Java
String cmd = String.format("sh -c rm -rf /tmp/%s", request.getParameter("username"))Runtime.getRuntime().exec(cmd)
Go
cmd := exec.Command(fmt.String("rm -rf /tmp/%s", req.FormValue("username"))
err := cmd.Run()
Some Server-Side Template Injection
Ruby on Rails
render inline: "Hello, #{params[:name]}!"
Python / Jinja
from jinja2 import Environment
name = request.GET.get('name')Environment().from_string('Hello ' + name + '!').render()
Some Cross-Site Scripting?
<html> <head> <title>{{ title }} - My Site</title> <style> body { color: {{ theme['color'] }}; } </style> </head> <body> <script type="text/javascript"> var init = {{ data }}; </script>
<a href={{ home_url }}>Home</a>
</body></html>
Some Cross-Site Scripting?
<html> <head> <title>{{ title }} - My Site</title> <style> body { color: {{ theme['color'] }}; } </style> </head> <body> <script type="text/javascript"> var init = {{ data }}; </script>
<a href={{ home_url }}>Home</a>
</body></html>
HTML Context
CSS Context
JavaScript Context
HTML Attribute Context
Web Programming is Metaprogramming
SQL / NoSQL
HTTP, HTML, JavaScript, JSON, CSS, ...
HTTP, JSON, XML, Form Data...
HTTP, JSON, XML, ...HTML, JavaScript, CSS, ...
Web Programming is Compiler Construction
SQL / NoSQL
HTTP, HTML, JavaScript, JSON, CSS, ...
HTTP, JSON, XML, ...
HTTP, JSON, XML, ...HTML, JavaScript, CSS, ...
Compiler Components
Lexer
Parser
Semantic Analyzer
Code Generator(s)
Source Code
Token Stream
Abstract Syntax Tree
Semantic Graph
IntermediateRepresentations
Compiled Code
Web Programming is Compiler Construction
SQL / NoSQL
HTTP, HTML, JavaScript, JSON, CSS, ...
HTTP, JSON, XML, ...
HTTP, JSON, XML, ...HTML, JavaScript, CSS, ...
Via String ManipulationWith Untrusted Values!
SQL Injection Prevention
ORM
User.where(email: params[:email])
Query Parameterization
User.where(["email = ?", params[:email]])
Manual escaping
email = ActiveRecord::Base.connection.quote_string(params[:email])
query = "SELECT * FROM users WHERE email = #{email}"
ActiveRecord::Base.connection.execute(query)
Remove Unsafe Interfaces
db.execute(...) NO!
system.run(...) NO!
blah.html_safe NO!
{{ … | safe }} NO!
blah.innerHTML = ... NO!
But I Want To...
schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
result = query(<<-SQL, name)
SELECT distinct i.relname, d.indisunique, d.indkey, t.oid
FROM pg_class t, pg_class i, pg_index d
WHERE i.relkind = 'i'
AND d.indexrelid = i.oid
AND d.indisprimary = 'f'
AND t.oid = d.indrelid
AND t.relname = '#{table_name}'
AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
ORDER BY i.relname
SQL
Types to the Rescue?
User.where("name = '#{params[:email]}'")
SecurityError in UsersController#search:
Cannot add dangerous input to String
Is This a Good Idea?
mab = Markaby::Builder.new
mab.html do
head { title "Boats.com" }
body do
h1 "Boats.com has great deals"
ul do
li "$49 for a canoe"
li "$39 for a raft"
li "$29 for a huge boot that floats and can fit 5 people"
end
end
end
Context-Aware Auto-Escaping
<html> <head> <title>{{ title }} - My Site</title> <style> body { color: {{ theme['color'] }}; } </style> </head> <body> <script type="text/javascript"> var init = {{ data }}; </script>
<a href={{ home_url }}>Home</a>
</body></html>
HTML Context
CSS Context
JavaScript Context
HTML Attribute Context
How?
Quality, simple, portable libraries (e.g. libnacl, libpasta)
Make it “standard” in new web frameworks
Have the “cool kids” (Google, Facebook, etc.) push it
How?
Quality, simple, portable libraries (e.g. libnacl, libpasta)
Make it “standard” in new web frameworks
Have the “cool kids” (Google, Facebook, etc.) push it
Top Related