Most learning materials for web app pentesting focus on “old school” apps. Maybe they have a little jQuery sprinkled in, but most of the heavy-lifting happens server-side. With the dawn of frontend frameworks like AngularJS, Vue, and React and Single-Page Applications, the way web apps are developed is changing, and pentesters need to keep up. This talk runs through common security issues with and approaches to testing these new apps.
2. About me
Work in Threat & Vulnerability
Management (pentesting, vulnerability
assessment / management, threat
modelling, etc.) at Accenture Security
out of Atlanta office
Mostly do web app assessment /
pentesting work
Like making ice cream, baking,
cooking
Like bad movies like The Room, Miami
Connection, Samurai Cop, and
R.O.T.O.R.
Don't like writing "About me" slides
3. Motivation
Most introductory resources in web appsec focus on old-school app
architectures
The goal: look at issues and approaches pertinent to modern apps, but still
keep things basic
"Modern":
Implements large portion of presentation and business logic with frontend
framework like Angular[JS], Vue, or React
Communicates with server via API, usually RESTful
Not: uses this month's hot new state management lib
Based on my own experience – I don't talk about React much not because it's
not important, but because I haven't dealt with it much in client work
5. Data binding
Frameworks like AngularJS & Vue
do a lot, but what we're most
interested in here is data binding
Instead of making manual edits to
the DOM, developers can use
client-side templates to
interpolate data into the page
https://jsfiddle.net/4nxwyd3y/18/
6. Default protection
They protect against XSS by
default: data bindings (e.g., via {{
}} expression syntax) are
automatically encoded
Two main ways for an application
to nonetheless be vulnerable:
Encoding mechanisms intentionally
disabled
Client-side template injection
https://jsfiddle.net/4nxwyd3y/18/
7. Disabled protections
At some point, devs will want to
insert raw HTML
Frameworks provide means to
accommodate this need
Raw HTML + unescaped user input
= XSS, as always
Framework Example sink
AngularJS
(1.x)
$sce.trustAsHtml, ng-bind-
html-unsafe (removed in
1.2)
Angular (2+) bypassSecurityTrustHtml
Vue Triple curly braces (v1
only), v-html
React dangerouslySetInnerHTML
9. Client-side template injection
Applications – especially legacy
ones with a new coat of paint –
may mix client- and server-side
templating
Server-side may have point where
untrusted user input is reflected
Recall:
A server-side templating engine
will generally encode <, >, ', and "
The client-side framework will use
{{ and }} to demarcate expressions
Hmm…
Resources
XSS without HTML: Client-Side
Template Injection with AngularJS
So you thought you were safe using
AngularJS. . . . Think again!
ng-owasp: OWASP Top 10 for AngularJS
Applications
Vue.js serverside template XSS
example
Exploiting Script Injection Flaws in
ReactJS Apps
10. Client-side template injection
AngularJS expressions are
"JavaScript-esque"
Can access object properties,
perform simple operations, etc.
No access to important globals like
document and window by default,
but…
Previous versions had sandbox
meant to prevent access, but
security researchers produced a
litany of escapes
1.6 removed sandbox entirely
Resources
AngularJS Developer Guide:
Expressions
AngularJS 1.6 Expression Sandbox
Removal
12. Expression breakdown
{} An object
{}.toString A function
{}.toString.constructor The function constructor
{}.toString.constructor('js here') A function dynamically constructed
from a string
{}.toString.constructor('js here')() Said function, called
14. What about quotation marks?
Our expression doesn't need angle brackets, but what if quotation marks are
filtered/encoded, as they should be (and in my experience, have been)?
Use ` backticks (new ECMAScript feature, template literals)? Nope,
expressions are JS-ish-but-not-JS, so AngularJS won't parse `
Use String.fromCharCode? Nope, can't access String global object in
expression
But wait, can't we just do the same {}.toString.constructor footwork to
replace String?
15. Expression breakdown – string without
quotes?
{} An object
{}.toString A function
{}.toString.constructor The function constructor (i.e., not
String)
{}.toString.constructor.fromCharCode() A call to fromCharCode()
17. Quoteless strings & the joys of odd type
conversions
![] The Boolean value false (I don't get it
either…)
[] An empty array… or an empty string???
+ Addition… or string concatenation with
funky automatic type conversion
![]+[] Boolean gets converted to string to be
concatenated with empty string, and
now we have the string "false"
• I'm not a JS expert – this explanation probably has issues
• Recommended reading: Web Application Obfuscation by Heiderich, Nava,
Heyes, and Lindsay
18. Expression breakdown – the cool way
![]+[] "false"
(![]+[]).constructor The String constructor
(![]+[]).constructor.fromCharCode The fromCharCode method
(![]+[]).constructor.fromCharCode(97,1
08,101,114,116,40,100,111,99,117,109,
101,110,116,46,100,111,109,97,105,11
0,41)
"alert(document.domain)"
20. The simple way
If {}.toString gets us the
toString function, {}.toString()
should get us an empty string
I tried it before and it didn't work,
I swear… apparently I tried it
incorrectly…
It does work, and the "cool way" is
unnecessary
https://jsfiddle.net/4nxwyd3y/19/
22. Rough typical app structure
Frontend
(presentation, business logic)
Angular[JS]
Vue
React
REST API
(business logic)
Jersey
Express
ASP.NET Web API
DB
(persistence)
Oracle
MongoDB
MS-SQL
23. Poking at frontend
code
There's a fair chance all/most
modules in the app have been
mushed together into one file
via Webpack or similar
This could include logic & API
calls meant for other roles
So look in source for potentially
juicy XHRs (easier said than
done…)
Some apps may also use
AngularJS's $resource service
24. REST API docs
If available, it's useful to get a
copy of API docs, esp. in
Swagger/OpenAPI or WADL format
Docs not necessarily available by
default
APIs following the HATEOAS
constraint may be partially self-
documenting
Framework Common doc path
Generic /, /doc, /v1/api/doc, etc.
Jersey /application.wadl[detail=true],
/<resource>/application.wadl
RESTEasy /application.xml
CXF /<WAR>/<servlet>/services,
/<WAR>/<servlet>/<resource>/
?_wadl
Spring w/
Springfox
/v2/api-docs
ASP.NET Web
API w/
Swashbuckle
/swagger/docs/v1
27. REST in 10 seconds
Get a list of books GET /api/books
Create a book POST /api/books
{"title": "Based on a True Story", "author":
"Norm MacDonald"}
Retrieve a book GET /api/books/243
Edit a book PUT /api/books/243
{"title": "Based", "author": "Norm"}
Delete a book DELETE /api/books/243
28. Logic vulnerabilities
Since more app logic is handled client-side, there are more opportunities for
devs to forget to check security-relevant logic server-side
Simple operations like displaying the name of the logged-in user in the upper-right
can involve API calls (e.g., GET /users/current)
While plenty of apps do it "incorrectly", REST APIs generally operate on
"resources" (like a user) rather than specifying particular "actions" (like
changing a user's email)
Operations that might obviously need to be restricted as "actions" – or never
be made available at all – may slip through the cracks as CRUD operations on
"resources"
29. Logic vulnerabilities
Real-world examples
User's role could be elevated from unprivileged to admin with a PUT to
/users/current
Unprivileged users could POST to /users and create new (admin) users
Answers to user's password-reset questions could be retrieved with GET to
/users/<ID>
User could change another user's password reset code – and hijack that user's
account – with a PATCH to /users/<ID>
30. Postman
If you find yourself hand-writing
API calls in Burp Repeater or
curl too much, try Postman
Can import API docs if you have
them
Postman environments and/or
collections ("inherit
authorization from parent")
features can be useful for
authn/authz testing
32. CORS background: the same-origin
policy
JavaScript can use XMLHttpRequest (Ajax) calls to fetch the contents of the
page / response of an API call
If the withCredentials property is set to true, cookies, auth headers, and client
certs will be sent
What stops attacker.com from reading my data from gmail.com?
Under the same-origin policy, JavaScript on attacker.com is forbidden from
reading responses to Ajax requests made to gmail.com
Origin: (scheme, hostname, port)
E.g., (https, gmail.com, 443)
33. Cross-origin resource sharing
Developers can override this behavior with
CORS
It is a bit more involved than this, but if:
brian.com made an Ajax call to
GET
https://hysell.com/api/private
hysell.com responded with the
header Access-Control-Allow-
Origin: https://brian.com
hysell.com responded with the
header Access-Control-Allow-
Credentials: true
…then the browser would send the request
with cookies etc. & allow brian.com to
read the response
34. CORS pitfalls
Browser sends "Origin" header with request (e.g., Origin:
https://attacker.com)
Sometimes misconfigured apps reflect back value of request's Origin header in
value of Access-Control-Allow-Origin
When this is the case & Access-Control-Allow-Credentials is true, third-party
sites can read API data of logged-in users with impunity!
Caveat: only applies to credentials handled by the browser like client certs,
cookies, or HTTP basic auth headers; not, e.g., to bearer tokens stored in a header
35. Framework vulnerabilities
Applications will often use some
kind of framework or plugin to
build their REST APIs, e.g., Restlet,
RESTEasy, Jersey, or CXF
Just because the frontend JS talks
to the API in JSON doesn't mean
that's all the REST backend
understands
Frameworks will often accept XML,
and sometimes even more exotic
inputs like YAML or even serialized
Java objects (!!!)
Framework Input CVE
Struts REST XML CVE-2017-
9805
RESTEasy YAML CVE-2016-
9606
RESTEasy Serialized
objects
CVE-2016-
7050
Restlet XML CVE-2017-
14868, CVE-
2017-14949
36. Framework vulnerabilities
Frameworks may pass YAML, XML,
etc. to insecure object
unmarshallers
E.g., the recent Struts REST RCE –
XML was handled by the XStream
unmarshaller, which can be
leveraged to create dangerous Java
objects
Older (…and not so much older)
frameworks may have XXE
vulnerabilities processing XML
Resources
Entity provider selection confusion
attacks in JAX-RS applications
Unsafe JAX-RS: Breaking REST API
Java Unmarshaller Security