New Sandbox Bypass in 1.4.7 - XSS with AngularJS 0x3
New Sandbox Bypass in 1.4.7 - XSS with AngularJS 0x3
Walkthrough of the sandbox bypass for version 1.4.7 by Gareth Heyes that leads to XSS in AngularJS.
mario heiderich @0x6d6172696f (https://cure53.de/)
gareth heyes @garethheyes
XSS without HTML: Client-Side Template Injection with AngularJS
http://blog.portswigger.net/2016/01/x…
An Abusive Relationship with AngularJS
https://vimeo.com/165951806
=[ 🔴 Stuff I use ]=
→ Microphone:* https://geni.us/ntg3b
→ Graphics tablet:* https://geni.us/wacom-intuos
→ Camera#1 for streaming:* https://geni.us/sony-camera
→ Lens for streaming:* https://geni.us/sony-lense
→ Connect Camera#1 to PC:* https://geni.us/cam-link
→ Keyboard:* https://geni.us/mech-keyboard
→ Old Microphone:* https://geni.us/mic-at2020usb
US Store Front:* https://www.amazon.com/shop/liveoverflow
=[ ❤️ Support ]=
→ per Video: https://www.patreon.com/join/liveover…
→ per Month: / @liveoverflow
=[ 🐕 Social ]=
→ Twitter: https://twitter.com/LiveOverflow/
→ Website: https://liveoverflow.com/
→ Subreddit: https://www.reddit.com/r/LiveOverflow/
→ Facebook: https://www.facebook.com/LiveOverflow/
=[ 📄 P.S. ]=
All links with ”*” are affiliate links.
LiveOverflow / Security Flag GmbH is part of the Amazon Affiliate Partner Programm.
#WebSecurity
Content
6.45 -> In the last video we used the very simple
sandbox bypass from version 1.0.8 and checked
13.01 -> why it doesn’t work anymore for 1.4.7.
16.71 -> After that we started to look at the sandbox
bypass from gareth heyes for this new version.
22.4 -> In this video we will continue where we left
off last time and debug the AngularJS code,
28.18 -> evaluating the evil expression that will lead
to an alert.
32.07 -> So as a quick reminder, the sandboy bypass
looks like this.
35.66 -> It has two parts.
37 -> The first part attempts to overwrite the charAt
function with another function.
41.23 -> Which hopefully screws up angular internally.
43.5 -> And the second part is dollar eval, which
is the angular eval to evaluate an expression.
50.15 -> So this is basically a new expression inside
of the other expression.
55.239 -> Also remember that a lot of stuff has changed
internally from the old version.
59.28 -> The concept is the same - angularjs parses
an expression, evaluates it and somehow executes
64.61 -> it.
65.81 -> Just how it’s done has changed.
67.9 -> We will see what it does by stepping through
the code.
70.77 -> Ok.
71.77 -> Let’s start for real.
73.009 -> Here we are at the first breakpoint that we
hit after we load the page.
76.409 -> I placed this breakpoint into a function called
lex.
80.42 -> This is the Lexer.
81.799 -> Wikipedia tells us that lexical analysis is
the process of converting a sequence of characters
88.459 -> into a sequence of tokens.
91.009 -> The lexical analysis is basically the first
step in a compiler.
95.289 -> So if you are a computer science student and
always wondered why the heck you ever need
99.549 -> to know compiler construction, here is a real
life example.
103.939 -> Also if you look at the call stack you can
see that the lexer is called from somewhere
108.02 -> with the name AST compiler, which stands for
“Abstract Syntax Tree” compiler.
115.7 -> It sounds weird but that is literally what
this is.
119.679 -> AngularJS implements a compiler that takes
an agnularjs expression, which looks like
125.63 -> javascript and compiles it to real javascript.
128.649 -> There is a damn compiler inside of angularjs.
132.349 -> A compiler that compiles something like javascript
to javascript.
135.79 -> Anyhow… still freaks me out.
137.87 -> Back to the lexer….
139.349 -> So.
140.349 -> This function has one parameter called text.
142.9 -> And text contains the current angularjs expression.
146.329 -> According to wikipedia this lex function should
parse a string and extract tokens from it.
152.239 -> And after our breakpoint we can see a while
loop that does exactly that.
157.26 -> This while loop iterates over the full length
of text.
160.33 -> And in each iteration it will use text.charAt
to get the next character of the string.
167.75 -> So the first character would be the single
quote from the string a.
172 -> When we step one step further we get to an
if that checks if the character is a single
177.329 -> or double quote.
179.159 -> Which is obviously the case.
180.519 -> So we will follow this and call the helper
function - readString.
184.12 -> Because this single quote is an indication
that a string starts.
188.23 -> And this whole while loop is full of ifs and
helper functions like that.
193.65 -> But in the end we will get an array of tokens.
196.319 -> So lets continue until this next breakpoint.
199.5 -> Now we should have all tokens extracted from
the expression.
203.79 -> This.tokens is now an array of Objects.
207.73 -> The first object, or token, is the string
“a”.
211.569 -> Because it’s a fixed string this is also
considered a “constant”.
215.739 -> The next token is the dot between the string
and the constructor.
218.849 -> And the third token is the constructor.
221.819 -> Which is considered an identifier.
224.4 -> All variable names and function names etc.
are identifiers.
230.09 -> Also for example the 8th token is the equal.
232.989 -> Which is an operator.
234.04 -> And before that we have the charAt function
name, which is also an identifier.
239.709 -> Now when I press continue until we hit the
next breakpoint a loooot of stuff will happen.
245.519 -> And we all skip that.
247.519 -> Basically this lexical analysis to extract
the tokens was the start of compilation and
253.069 -> now we will have a look at the result of the
compilation.
256.25 -> So we skip the whole complicated compiling
part.
259.35 -> So continue.
260.35 -> And now we are here.
262.019 -> At the end of AST Compile.
264.88 -> Just before our breakpoint we have here this
variable called fnString.
269.17 -> Stands for function string.
270.42 -> And I printed that string to the console log
down here.
274.63 -> And this.
275.63 -> is . the compiled javascript code.
277.73 -> That is the result of compiling our angular
expression to javascript.
282.44 -> This looks a bit awful to read, so let’s
copy it over into javascript beautifier to
286.57 -> indent it properly and have a look at it.
290.42 -> Sweet.
291.48 -> That looks more readable.
293.22 -> It might look crazy and complicated at first,
but it’s actually pretty simple.
297.31 -> So first of all, this code starts like our
expression with the string a.
300.97 -> And stores it in the variable 4.
303.42 -> Then it attempts to get the constructor from
variable 4.
306.59 -> So the constructor of the string.
309.09 -> After that angularjs added a function ensureSafeObject
to check if the constructor of variable 4
314.54 -> is safe.
315.54 -> And because that is just the String constructor,
it’s considered safe.
319.14 -> Remember that this function was responsible
for the exception when we tried to access
324.04 -> the function constructor with the old bypass.
328.51 -> After that the constructor is moved into variable
3 and checked if it has the property prototype.
333.09 -> If that’s the case, the reference to prototype
is saved in variable 1.
339 -> And as a last step we check if the string
prototype stored in variable 1 has a charAt
345.43 -> property.
346.43 -> Now we are done with the left side of the
assignment
349.03 -> Up next is the right side.
351.2 -> Here we start also with a string.
352.88 -> String b is moved into variable 5 and follows
it up with referencing concat of it and moving
359.02 -> it into variable 0.
361.42 -> Then angularjs checks if charAt of variable
1 is a safe object.
365.99 -> But that is obviously just the normal charAt
function and that’s considered safe.
370.46 -> Afterwards variable 1 itself is checked, because
we are about to assign something to the string
376.02 -> prototype in variable1 and angularjs want’s
to be sure it’s safe to assign something
380.57 -> to that object.
381.57 -> Man.
382.57 -> If angularjs would just know what is about
to happen.
386.07 -> Now the crucial part.
387.43 -> We assign the concat function in variabvle
0, to the charAt function of the String prototype
393.01 -> in variable 1.
394.47 -> Now the first part of the exploit is done.
398.45 -> At this point charAt should have laid an alien
egg inside of angular’s body, which is about
403.01 -> to hatch and break out of angular’s chest.
405.93 -> The following few lines are then the second
part of the exploit, which is fairly short.
410.84 -> It basically gets dolalr eval now from the
scope object, does some checks on those variables,
416.15 -> including the string parameter we pass to
dollar eval, but it’s just a string.
420.83 -> So all is safe.
422.38 -> And eval is called, which initiates another
parsing, compilation and execution of this
428.08 -> string.
429.08 -> Now that we understand the compiled code.
431.05 -> So let’s see what happens with that.
433.2 -> After our old breakpoint fnString is used
in a call to the good old Function constructor,
440.67 -> which will create an actual function that
can then later be called.
444.4 -> At the end it will return this function fn.
447.5 -> I’m about to hit continue again so we will
jump to our next breakpoint.
451.091 -> The next breakpoint is inside if ensureSafeObject.
452.16 -> That is one of the function called from the
compiled code.
453.61 -> So that means we are actually inside of our
executing expression.
455.07 -> Go!
456.07 -> Boom.
457.07 -> ok.
458.07 -> Ensure SafeObject.
459.07 -> In the call stack we can see that we are coming
from fn.
460.07 -> And fn is this compiled function.
461.72 -> You can pretty print this code by clicking
on the curley braces in the bottom left of
465.39 -> the source window.
466.52 -> Yep, this looks familiar.
468.78 -> Just what we looked at before.
470.74 -> Here is our string a.
471.74 -> And getting the constructor of it.
474.36 -> Etc.
475.36 -> When I now continue we are again in ensureSafeObject.
478.66 -> This time further down in the code.
481.01 -> Actually right before we assign and overwrite
charAt.
484.17 -> Just one more check before, the ensureSafeAssignContext.
486.78 -> Ok let’s continue a bit more, until we are
back inside of the lexer.
492.18 -> Why are we here again?
494.36 -> Well as you can see in the call stack we are
coming from fn.
499.34 -> And fn called dollar eval.
501.35 -> And dollar eval is just now triggering evaluation
and execution of this new expression string.
507.83 -> As expected, text is simply what we passed
to dollar eval.
512.44 -> But let’s step further.
514.88 -> We are again heading into the while loop that
is supposed to extract single tokens from
520.81 -> this character sequence.
523.44 -> The index starts again at 0.
525.67 -> So now angularjs tries to get the first character
from the string with charAt.
530.3 -> But charAt is not charAt anymore.
533.23 -> The alien hatches and feeds on angular’s
intestines.
536.48 -> Charat zero appends now zero to the string,
instead of returning a single character.
544.03 -> So ch is super long and thus not the start
of a string.
549.97 -> It’s also obviously not a number.
552.76 -> BUT!
553.84 -> The validation function isIdent thinks that
this is now an identifier.
559.85 -> Remember that usually variables and function
names etc. are identifier.
565.3 -> That means that usually identifiers do not
contain special characters, such as the equal
570.651 -> or curly braces we have in this string.
574.25 -> And if we continue now to the end of the loop,
and look at the tokens, we can see that there
579.64 -> is only one token.
581.61 -> And It’s an identifier with our whole string.
584.55 -> That is just wrong.
586.14 -> An identifier should not have those weird
characters inside.
589.73 -> If we continue now, we hit the next breakpoint
at the end of compilation.
593.98 -> And we can have a look at the resulting javascript
code.
597.55 -> Let’s again copy it over to js beautifier
to see what happenned.
601.33 -> Ah.
602.33 -> You can already see here the part2 of our
exploit embedded in the javascript code.
609.08 -> You can also see that it’s S. Dot.
611.93 -> exploit blah blah.
613.83 -> Remember that all expressions are evaluated
against the scope object?
616.89 -> Well because angularjs thought we had an identifier
in our expression, it placed that identifier
622.83 -> in the compiled code by checking if the scope
object has such a proeprty.
629.64 -> In this case this totally blows up because
the identifier had non valid identifier characters.
636.94 -> When you ident it properly it becomes more
clear.
639.99 -> You can see now the start of our expression
with exploit equals 1 and the three closing
644.92 -> curley braces.
646.45 -> Then the breakpoint and then the alert one.
649.23 -> So when we continue now, we should hit that
breakpoint.
653.17 -> Boom.
654.17 -> Indeed.
655.17 -> We are inside of the compiled code at the
breakpoint.
658.94 -> Pretty print it again.
659.94 -> And let’s enjoy this beauty for a second.
664.13 -> Then hit continue, which will execute alert.
669.52 -> Awesomeee!
671.1 -> And this is how the angularjs sandbox bypass
for version 1.4.7 works.
676.68 -> We overwrite the charAt function that is shared
for all strings.
680.35 -> Which breaks how angularjs parses expressions
allowing us to inject bad characters as an
685.86 -> identifier in the compiled code which we can
abuse to break out and write arbitrary javascript
691.93 -> code.
Source: https://www.youtube.com/watch?v=Hium4FVAR5A