what is it? why should i care? how can i avoid it? - aws
TRANSCRIPT
XSS EverywhereXSS EverywhereWhat is itWhat is it
Why should I careWhy should I careHow can I avoid itHow can I avoid itNick Blundell mdash AppCheck NG
About UsAbout UsWe provide a vulnerability scanning service viasoware forged through day-to-day pen testingexperience We specialise in Web App securityWe live and breathe vulnerability research and wecontinue to push our scanning technology to thelimits and beyond
httpappcheck-ngcom
OverviewOverviewWhat is a Web ApplicationWhat is XSSHow can we avoid itHow can it be mitigated
What is a Web ApplicationWhat is a Web Application
It is an application that involves your Browser and aWeb Server
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
About UsAbout UsWe provide a vulnerability scanning service viasoware forged through day-to-day pen testingexperience We specialise in Web App securityWe live and breathe vulnerability research and wecontinue to push our scanning technology to thelimits and beyond
httpappcheck-ngcom
OverviewOverviewWhat is a Web ApplicationWhat is XSSHow can we avoid itHow can it be mitigated
What is a Web ApplicationWhat is a Web Application
It is an application that involves your Browser and aWeb Server
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
OverviewOverviewWhat is a Web ApplicationWhat is XSSHow can we avoid itHow can it be mitigated
What is a Web ApplicationWhat is a Web Application
It is an application that involves your Browser and aWeb Server
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Web ApplicationWhat is a Web Application
It is an application that involves your Browser and aWeb Server
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
It is an application that involves your Browser and aWeb Server
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
You put a URL in your browser and it loads a (HTML)page
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Your browser then renders the page from theresponses HTML which looks like this
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltpgtMy first paragraphltpgt
lta href=some_other_pagegtVisit other pageltagt
ltbodygt
lthtmlgt
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
The HTML usually also contains scripts typicallyJavaScript which the browser executes alongsiderendering the page
This script execution is what enables the dynamicnature of day-to-day web applications
ltDOCTYPE htmlgt
lthtmlgt
ltbodygt
lth1gtMy First Headinglth1gt
ltscriptgtwindowalert(Hello World)ltscriptgt
ltbodygt
lthtmlgt
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
You Have MailYou Have Mail
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Congratulations You have WONCongratulations You have WONan iPhone Xan iPhone X
Well done Ben As a long-term and valued member ofour online banking service you were shortlisted and
selected as the lucky winner of an iPhone X
Claim your iPhone X
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thats FantasticThats Fantastic
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Hmmm but wait
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Erm why is my bank balance now at zero
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Probably just a temporary issue
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
and nice about the iPhone
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Time for a little scrutinyTime for a little scrutinyThat link in my email
points to this (yikes)httpsecure-bankcom8686mini_pres_appvanilla
report_id=A6FE254233Cscript3Epayload203D202224(2723firstName27)val(27Evil27)3B24(2723lastName27)val(27Hacker27)3B24(2723account_num27)val(1236532)3B24(2723sort_code27)val(547345)3B24(2723amount27)val(12354434)3B24(2723do_transfer
27)click()220dsetTimeout(function()w=$(22iframe22)[0]contentWindow0dweval(payload)1000)3B24(22body22)prepend(2
73Cimg20src3D222Fcongratsjpg2220style3D22margin-le3A300px223E27)3Cscript3E3Ciframe20name=22theFrame22
width=221002220height=2230022src=22transfer_money223E
Claim your iPhone X
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Time for a little scrutinyTime for a little scrutinyBut still just looks like some long URL and Imused to seeing obscure stuff like thisAnd it is pointing to the secure banking applicationthat Im familiar with secure-bankcom
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Lets make that clearerLets make that clearerIf we URL decode that (ie change patterns like 3C tothe characters they represent like lt) it looks likethis
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtpayload =
$(firstName)val(Evil)$(lastName)val(Hacker)$(account_num)val(1236532)$(sort_code)val(547345)$(amount)val(12354434)$(do_transfer)click()
setTimeout(function()w=$(iframe)[0]contentWindowweval(payload)1000)$(body)prepend(ltimg
src=congratsjpg style=margin-le300pxgt)ltscriptgtltiframename=theFramewidth=100 height=300src=transfer_moneygt
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
This doesnt look right to meThis doesnt look right to me$(firstName)val(Evil)$(lastName)val(Hacker)
$(do_transfer)click()
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Looks like the intention is hiddenLooks like the intention is hiddenherehere
They are masking (ie hiding) something with thisimage
$(body)prepend(ltimg src=congratsjpg left300pxgt)
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Looks like the intention is hiddenLooks like the intention is hiddenherehere
Lets take away the mask and see
Claim your iPhone X (unmasked attack)
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Nooooo we Just got XSS-edNooooo we Just got XSS-edThis was a bog standard XSS attackwith a devastating impactA simple slip up can result in stuff like thisLets figure out how all of that just happened
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Recall that the web server responds to the browserwith HTML pagesThese pages have a structure which describes howthe page is to be laid out visuallyThat structure can also contain script elementswhich run code on the page to do fancy stuff likedisplaying a new social media event
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Usually an application does not want the user todirectly control the HTML structure perhaps just portions of it like actual content and definitely the application does not wantusers to add arbitrary script elements to the pages
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Confidentiality is lost when a single instance of XSSoccurs where a users input is mishandled to allow it toalter the wider HTML structure of a pageAn attacker will usually then exploit this to run ascript on a page accessed by another user so the hackers script will run within another usersprivateauthenticated session
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
What is a Cross-Site ScriptingWhat is a Cross-Site Scripting(XSS) Vulnerability(XSS) Vulnerability
Depending on the context an attack can be deliveredeither
Directly by a craed URL to a victim (via email otherwebsites etc) known as a Reflected XSS attackIndirectly by the hacker laying a trap in theapplication itself for victims to stumble uponknown as Persistent XSS
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How bad can it beHow bad can it beUsers may be exploited to the hackers financialadvantageAdmin accounts may be targeted leading to fullapplication compromise
With admin control of the application an attackerwill then seek to compromise the host and all dataaccessible from it usually through some privileged admin featurelike for system configuration
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Lets start with the basics aLets start with the basics avanilla examplevanilla example
When we are logged into our online banking app andwe view a report on the following URL
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
A vanilla exampleA vanilla exampleThe first thing we notice is that the ID of the report isreflected in the page from the web server
Requesting this URLhttpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423
Gives this response with the value reflectedlth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
A vanilla exampleA vanilla exampleSo the next question on an attackers mind is
How does the application respond if I try to input thespecial HTML tag brackets lt and gt
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltbgtevilltbgt
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltbgtevilltbgt
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
A vanilla exampleA vanilla example
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
A vanilla exampleA vanilla exampleSo the hacker can create an HTML tag on the victimspage how about running a script in the victims page(ie in their authenticated session)
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We see the script tag was injected without anyinterference through validation
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltscriptgtalert(evil)ltscriptgt
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
A vanilla exampleA vanilla exampleAnd so we see the hackers script executesNote oen XSS is demonstrated by popping openan alert box this is proof the hacker can perform any action onthe victims page
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerRight Mr Hacker you mess with us we mess with
you
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Approach If the hacker tries to inject a script tag weare going to strip the keyword out
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Application responds
We Win Boof the script keyword was stripped out sono malicious script will execute
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Application does
We Lose we stripped only lowercase script but HTMLtags are case insensitive so the hacker wins again
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Approach Strip out the keyword script whatever thecase of its characters
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Lose Hmmmm this guy knows some tricks Heanticipated me stripping out the keyword and createda keyword sandwich which made my efforts look really
lame
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltsCriPtgtalert(evil)ltsCriPtgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Approach If the hacker is going to sandwichkeywords like that I will now repeatedly strip out the keyword scriptuntil there are no more
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltsCrScripTiPtgtalert(evil)ltsCrScripTiPtgt
Application does
We Win The keyword script is stripped out regardlessof its case and if sandwiched
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltgtalert(evil)ltgt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)But but but then the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Lose Whaaat So they injected an img tag insteadof a script tag to run a script
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423ltimg src=1 onerror=alert(evil)gt
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Okay it turns out there are many ways to cause ascript to run in a browser so blocking the keywords like script is a completewaste of time
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)Right thats it Mr HackerWe know what needs to be doneStrip out any tag brackets so these lt and gtThen an attacker can inject no tags into the page noscript no img no nothing
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 4)Thwarting the Attacker (Take 4)So now when the hacker does
httpsecure-bankcom8686mini_pres_appvanillareport_id=A6FE25423ltimg+src=1+onerror=alert(evil)gt
Application does
We Win Ha ha Now you cannot create any HTML tags atall
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423img src=1 onerror=alert(evil) [No tag brackets]
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Job DoneJob DoneNo more XSS for me )
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just News just ininA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets from all user input
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appattr_valuereport_id=A6FE25423
lth2 id=A6FE25423gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe hacker found this then created a yet stranger
payload like thishttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Lose In this context they didnt even need to add anew tag to get execution they just added an event
attribute to an existing tag
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerOkay Wise Guy I can see what you are doing hereand I know just what to doI will strip out quotes and double quotes too so you dont try any moretricks like that
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the Attackerhttpsecure-bankcom8686mini_pres_appattr_value
report_id=A6FE2542327+onmouseover=alert(27evil27)+foo=27
We Win Ha ha With your quotes stripped out youcannot break out of the quoted attribute value to add a
script executing attribute
lth2 id=A6FE25423 onmouseover=alert(evil) foo=gtViewing Reportlth2gt
Client Mr Jones
Report ID A6FE25423 onmouseover=alert(evil) foo=
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Home FreeHome FreeDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotesThere must be some mistake surely
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThere is another part of my application that reflects
input within a script tag like thishttpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564
lth2gtViewing Reportlth2gt
Client Mr Jones
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564
ltscriptgt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Lose The devils They found a place in a scriptwhere I reflected input without quotes - so they didnt
even need to use a quote (Id have stripped) to escape
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerOkay to reward your tenacity Mr Hacker Im goingto trap all of my input between quotes
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerNow when the hacker does this
httpsecure-bankcom8686mini_pres_appscript_unquotedreport_id=1236564-alert(1)
We Win Have that Mr Hacker Your attack is nowtrapped as a simple string and can no longer execute
Report ID ltspan id=id_placeholdergtNoneltspangt
ltscriptgt
documentgetElementById(id_placeholder)innerText = 1236564-alert(1)
ltscriptgt
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Hang up Your Hat Mr HackerHang up Your Hat Mr HackerDefinitely no more XSS for me now )
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I stripped out tag brackets and quotes and I ensured all input was trapped betweenquotesThis is becoming te di ous (
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Client Mr Jones
Report link lta onclick=log(Report opened + A6FE25423)gtlinkltagt
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe hacker found this then did this
httpsecure-bankcom8686mini_pres_appevent_attrreport_id=A6FE2542326apos3b-alert(1)-26apos3b
We Lose but it is not clear why from this since itseems they did not break out of the quotes so how
on Earth did it manage to execute
lth2gtViewing Reportlth2gt
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenWe need to understand what HTML entity encoding is
to understand how this attack succeeded
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So What is HTML EntitySo What is HTML EntityEncodingEncoding
Usually when we have a text-based structure like anHTML page there is a way of escaping special characters sothey can be displayed literally and so without being interpreted dangerously bythe browser as part of the wider HTML structure
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
HTML Entity EncodingHTML Entity EncodingSo encodings of key characters are encoded like this(with many other possible representations)
lt becomes ampltgt becomes ampgt becomes ampapos becomes ampquotamp becomes ampamp
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So how did it happenSo how did it happenSubtle insight When the browser parses tag attributes
it automatically HTML decodes their values
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So how did it happenSo how did it happenSo this
gets interpreted by the browser as this
So the hacker bypassed my quote stripping by encodingthe quote character in a way I didnt anticipate
Report link lta onclick=log(
Report opened + A6FE25423ampapos-alert(1)-ampapos
)gtlinkltagt
Report link lta onclick=log(
Report opened + A6FE25423-alert(1)-
)gtlinkltagt
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerTwo can play this game lets also use HTML encoding mdash
but as a defence mdash by HTML encoding the inputhttpsecure-bankcom8686mini_pres_appevent_attr
report_id=A6FE2542326apos3b-alert(1)-26apos3b
We Win In your face Mr Hacker When they attemptthe bypass their input ends up double HTML encoded
so the attack fails
Report link lta onclick=log(
Report opened + A6FE25423ampampapos-alert(1)-ampampapos
)gtlinkltagt
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Im Riding on a High Mr HackerIm Riding on a High Mr HackerI have drunk deeply from the fountain of XSS
knowledge and now you must stand aside My Friend
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote charactersand then I HTML entity encoded all inputWHAT MORE CAN I DO
WHAT MORE CAN I DO
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThere is another part of my application that reflects
input like thishttpsecure-bankcom8686mini_pres_apphref_attrreport_id=A6FE25423
lth2gtViewing Reportlth2gt
Report ID A6FE25423
lta href=A6FE25423editgtEdit reportltagt
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe hacker found this then did thishttpsecure-bankcom8686mini_pres_apphref_attr
report_id=javascriptalert(1)
We Lose What is THAT thing Their rather elegantpayload did not rely on any quote breakout and was
unaffected by HTML encoding etc
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=javascriptalert(1)editgtEdit reportltagt
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenSo it turns out that attributes which take URLs can
actually run scripts when prefixed with a specialscheme
javascript will run JavaScriptvbscript will run visual basic (MS browsers)livescript will run a prehistoric relic of JavaScript(old old Netscape mdash Do not worry about this)
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Right lets block anyting that starts with one of thosescript schemesAnd we are not going to fall for the exact-case trickagain we will block these whatever the case
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)So when the hacker tries this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=jaVascRiPtalert(1)
We Win The script prefix is blocked whatever the case
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 1)Thwarting the Attacker (Take 1)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Lose Doh The swines just added a space in front ofjavascript so my match-at-the-start-of-the-input
would fail Browsers are unhelpfully lenient in parsingthings like this
lth2gtViewing Reportlth2gt
Report ID javascriptalert(1)
lta href=_javascriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Right lets block anything that simply contains one ofthose script schemes whatever the case
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVascRiPtalert(1)
We Win Their space trick is now also blocked by ourstuff
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 2)Thwarting the Attacker (Take 2)Then the hacker does this
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=java0ascriptalert(1)
We Lose Youve got to be kidding me They bypassedmy check for javascript by sticking a line-break
character in the middle which the browser completelyignores and executes regardless
lth2gtViewing Reportlth2gt
Report ID java
scriptalert(1)
lta href=java lt-- sneaky line break
scriptalert(1)editgtEdit reportltagt
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)Okay we have to be really careful when using inputwith URL attributes like this especially if they reflect the start of the URL likehere
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the Attacker (Take 3)Thwarting the Attacker (Take 3)In this case I am going to opt for a strong whitelisting of only the alpha-numeric characters that arerequired for a report ID
httpsecure-bankcom8686mini_pres_apphref_attrreport_id=20jaVa0AscRiPtalert(1)
We Win This blocks any of that weird stuff yet willallow the application to work as intended
lth2gtViewing Reportlth2gt
Report ID BLOCKED
lta href=BLOCKEDeditgtEdit reportltagt
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So Long and thanks for all theSo Long and thanks for all theFish Mr HackerFish Mr Hacker
The hour is late and my job here is done
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
But I ensured all input was trapped between quotesI stripped out quote characters
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
News just inNews just inA HACKER HAS JUST EXPLOITED XSS ON OUR
APPLICATION
and I HTML entity encoded all inputand I locked down the harder places with whitelistsThis cannot be happening to me mdash it must be astress-induced nightmareYes Im going to wake up soon please PLEASE
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe hacker did this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
We Lose But how This is not possible because wehave already added appropriate protection for thiscrude script kiddie payload mdash it was one of the first
things we tackled
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenThe page just exploited looks like this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423
Hmmmm But I dont see the input value A6FE25423reflected anywhere in this page
lth2gtViewing Reportlth2gt
Report ID ltspan id=report_idgtltspangt
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenAh wait a minute I see what this code is doing it is a
different beast altogetherltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happen
So my web server does not return a page with thevalue reflected in it but it does return a script that runs when the pageloads
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happen
and this script then reads the URL parameterURLSearchParams(windowlocationsearch)get(report_i
then updates a placeholder element with the value$(report_id)html(report_id)
ltscriptgt
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
ltscriptgt
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
How did it happenHow did it happenSo there is a reflection of the user input but ithappens only on the client-side (ie in the browser)The web server never touches the value so here allmy efforts of server-side validation are completelybypassed
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Introducing DOM-based XSSIntroducing DOM-based XSSSo just as we have seen lots of examples so far ofbuilding unsafe HTML on the server it is possible also for a script to dynamicallyupdate the page you are viewing in an unsafe way
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Introducing DOM-based XSSIntroducing DOM-based XSSThis vector is known as DOM-based XSS since itoccurs during execution of a script which directly updates the Document Object Model(DOM) (ie the parsed HTML page that you view aera page loads)
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerThe main problem here is that we use an unsafemethod html() to change the DOM such that raw HTML supplied by the hacker will beparsed and rendered as HTML
It is common to see stuff like this when thepossibility of malicious input has been completelyoverlooked
var report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)html(report_id)
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerClearly it was not intended for a report ID to everexpress a piece of HTMLLets instead use text() which sets the contentsof the placeholder tag as text just plain textvar report_id = new URLSearchParams(windowlocationsearch)get(report_id)
$(report_id)text(report_id)
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Thwarting the AttackerThwarting the AttackerSo now when the hacker does this
httpsecure-bankcom8686mini_pres_appdom_query_paramreport_id=A6FE25423ltscriptgtalert(evil)ltscriptgt
Their payload is simply (and shamefully) displayedand does not execute
We Win
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So XSS is Hard RightSo XSS is Hard Right and deadly
No wonder it gets everywhere
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
So XSS is Hard RightSo XSS is Hard Right
It is worth trying to understand the intricacies of XSS asmuch as possible if you do not want to fall victim to it
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Some general guidelinesSome general guidelinesIn whatever context trap input between quotes anduse context-appropriate escapingencoding stop apayload breaking out of those quotesOtherwise employ very tight valuecharacter whitelisting
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Some general guidelinesSome general guidelinesRemember Tag attribute values are HTML decoded asthe browser parses the HTML so hackers will try touse this fact to bypass validation
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Some general guidelinesSome general guidelinesBe really careful when using input in URL contextsespecially to avoid attacks which use the javascriptscheme
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Some general guidelinesSome general guidelinesDont neglect client side handling of input to makesure it cannot be written to the DOM in an unsafeway
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Some general guidelinesSome general guidelinesThink twice before mixing user input with rawJavaScript evaluation functions such as eval()setTimeout() etc
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Mitigation (and its Limitations)Mitigation (and its Limitations)There are three main mitigation approaches for XSS
(Though avoidance of XSS is the best mitigation)
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Mitigation (and its Limitations)Mitigation (and its Limitations)HttpOnlyHttpOnly Cookies Cookies
These stop a direct hijack of a users session byhiding session tokens (in cookies) from scriptsThough making it harder an attacker will usuallyfind an application specific way to steal the usersaccount via XSS such as by changing their emailaddress then triggering a password resetIt is a good general rule to set any sensitive cookiesas HttpOnly unless the application requires it to beotherwise
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Mitigation (and its Limitations)Mitigation (and its Limitations)Browser XSS BlockingBrowser XSS Blocking
Any scripts observed to be reflected from the requestare blocked from executing by the browserHowever it is an ongoing game of catch-up betweenthe blocking algorithm and new techniques whichbypass itIt is effective only for Reflected XSS so not Persistentor DOM-based XSSIn fact Microso has announced it will soon retireXSS blocking in Edge given the little gain it brings
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Mitigation (and its Limitations)Mitigation (and its Limitations)Content Security Policy (CSP)Content Security Policy (CSP)
Supporting browsers allow the web application tolock down sources of JavaScript executionSo a CSP policy might allow scripts to execute onlyfrom a reduced set of source URLsAnd may block the use of inline javascript such asevent handlers and script tagsIn practice this may require a substantial re-writingof application code since violations may stop theapplication from functioning correctly
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
Further ReadingFurther Reading(for Techs or to pass on to your Techs)(for Techs or to pass on to your Techs)
Must read
Great collection of security related browser quirks
httpswwwowasporgindexphpXSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
httpscodegooglecomarchivepbrowsersecwikisMainwiki
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions
We Looked atWe Looked atXSSXSSMore XSSThen a little more XSS still
Dr Nick Blundell mdash AppCheck NG
Thank YouThank YouI hope that was useful
Questions