This document discusses various web application security vulnerabilities like SQL injection and cross-site scripting (XSS) from the perspective of an attacker. It begins by introducing SQL injection and demonstrates how it can be used to extract hidden data like usernames and credit card numbers. It then covers XSS and how malicious scripts can be injected onto a page to hijack user sessions. Finally, it discusses ways to protect against these vulnerabilities like input filtering, output encoding, and prepared statements. The overall goal is to help understand common attacks and how to build more secure applications.
2. Colin O’Dell
Lead Web Developer at Unleashed Technologies
PHP developer since 2002
league/commonmark maintainer
PHP 7 Migration Guide e-book author
php[world] 2015 CtF winner
@colinodell
3. Goals
Explore several top security vulnerabilities from the
perspective of an attacker.
1. Understand how to detect and exploit common
vulnerabilities
2. Learn how to protect against those vulnerabilities
@colinodell
4. Disclaimers
1.NEVER test systems that aren’t yours without
explicit permission.
2.Examples in this talk are fictional, but the
vulnerability behaviors shown are very real.
@colinodell
6. OWASP Top 10
Regular publication by The Open Web Application
Security Project
Highlights the 10 most-critical web application
security risks
@colinodell
10. SQL Injection
Basics
$value = $_REQUEST['value'];
SELECT * FROM x WHERE y = '[MALICIOUS CODE HERE]' ";
$sql = "SELECT * FROM x WHERE y = '$value' ";
$database->query($sql);
14. tail –n 1 /var/log/apache2/error.log
MySQL error: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL
server version for the right syntax to use near
"password'" at line 1.
tail –n 1 /var/log/mysql/query.log
SELECT * FROM users WHERE username = 'admin' AND
password = 'password'';
$
$
15. tail –n 1 /var/log/apache2/error.log
MySQL error: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL
server version for the right syntax to use near
"password'" at line 1.
tail –n 1 /var/log/mysql/query.log
SELECT * FROM users WHERE username = 'admin' AND
password = 'password'';
$
$
~~
18. tail –n 1 /var/log/apache2/error.log
MySQL error: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL
server version for the right syntax to use near
"' test" at line 1.
tail –n 1 /var/log/mysql/query.log
SELECT * FROM users WHERE username = 'admin' AND
password = '' test';
$
$
19. tail –n 1 /var/log/apache2/error.log
MySQL error: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL
server version for the right syntax to use near
"' test" at line 1.
tail –n 1 /var/log/mysql/query.log
SELECT * FROM users WHERE username = 'admin' AND
password = '' test';
$
$
~~~~~~~~
20. ~~~~~~~~
SELECT * FROM users WHERE username = 'admin' AND
password = '' test';
SELECT * FROM users WHERE username = 'admin' AND
password = '';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR (something that is true);
SELECT * FROM users WHERE username = 'admin' AND
(true);
SELECT * FROM users WHERE username = 'admin';
21. SELECT * FROM users WHERE username = 'admin' AND
password = '' test ';
' test
22. SELECT * FROM users WHERE username = 'admin' AND
password = '' test ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' test ';
' test
~~~~~~~~~~~~~~~~~~~~
23. SELECT * FROM users WHERE username = 'admin' AND
password = ' ';
SELECT * FROM users WHERE username = 'admin' AND
password = ' ';
24. SELECT * FROM users WHERE username = 'admin' AND
password = '' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' ';
'
~~~~
25. SELECT * FROM users WHERE username = 'admin' AND
password = '' ' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' ' ';
' '
~~~~~~~~~~~~~~~~
26. SELECT * FROM users WHERE username = 'admin' AND
password = '' OR ' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR ' ';
' OR '
27. SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1 ' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1 ' ';
' OR '1 '
~~~~
28. SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1' ' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1' ' ';
' OR '1' '
~~~~~~~~~
29. SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1'=' ';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1'=' ';
' OR '1'='
30. SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1'='1';
SELECT * FROM users WHERE username = 'admin' AND
password = '' OR '1'='1';
' OR '1'='1
35. ' AND (SELECT id FROM user LIMIT 1) = '
Username
Password
admin
Log In
Real-Time MySQL View
36. ' AND (SELECT id FROM user LIMIT 1) = '
Username
Password
admin
Unknown error.
Log In
Error LogQuery Log
SELECT * FROM users WHERE username = 'admin' AND
password = '' AND (SELECT id FROM user LIMIT 1) = '';
37. ' AND (SELECT id FROM user LIMIT 1) = '
Username
Password
admin
Unknown error.
Log In
Query Log
MySQL error: Unknown table 'user'.
Error Log
38. ' AND (SELECT id FROM users LIMIT 1) = '
Username
Password
admin
Unknown error.
Log In
Query Log
MySQL error: Unknown table 'user'.
Error Log
39. ' AND (SELECT id FROM users LIMIT 1) = '
Username
Password
admin
Invalid username or password. Please double-check and try again.
Log In
41. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/123
SELECT * FROM books WHERE id = 123
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => 'The Great Gatsby',
'author' => 'F. Scott Fitzgerald',
'price' => 9.75
}
@colinodell
42. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/99999
SELECT * FROM books WHERE id = 99999
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
}
@colinodell
43. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/?????
SELECT * FROM books WHERE id = ?????
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => '',
'author' => '',
'price' => 0.00
}
@colinodell
44. SQL UNION Query
Column 1 Column 2 Column 3
The Great Gatsby F. Scott Fitzgerald 9.75
Column 1 Column 2 Column 3
Foo Bar 123
Column 1 Column 2 Column 3
The Great Gatsby F. Scott Fitzgerald 9.75
Foo Bar 123
UNION
@colinodell
45. SQL UNION Query
Column 1 Column 2 Column 3
The Great Gatsby F. Scott Fitzgerald 9.75
Column 1 Column 2 Column 3
(SELECT) 1 1
Column 1 Column 2 Column 3
The Great Gatsby F. Scott Fitzgerald 9.75
(SELECT) 1 1
UNION
@colinodell
47. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/99999 UNION SELECT number FROM creditcards
SELECT * FROM books WHERE id = ?????
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => '',
'author' => '',
'price' => 0.00
}
@colinodell
48. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/99999 UNION SELECT number AS 'title', 1 AS
'author', 1 AS 'price' FROM creditcards
SELECT * FROM books WHERE id = ?????
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => '',
'author' => '',
'price' => 0.00
}
@colinodell
49. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/99999 UNION SELECT number AS 'title', 1 AS
'author', 1 AS 'price' FROM creditcards
SELECT * FROM books WHERE id = 99999 UNION
SELECT number AS 'title', 1 AS 'author', 1 AS
'price' FROM creditcards
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => '',
'author' => '',
'price' => 0
}
@colinodell
50. SQL Injection - Data Disclosure
http://www.onlinebookstore.com/books/99999 UNION SELECT number AS 'title', 1 AS
'author', 1 AS 'price' FROM creditcards
SELECT * FROM books WHERE id = 99999 UNION
SELECT number AS 'title', 1 AS 'author', 1 AS
'price' FROM creditcards
$id = …;
$sql = "SELECT title, author, price FROM books
WHERE id = " . $id;
$data = $database->query($sql);
{
'title' => '4012-3456-7890-1234',
'author' => 1,
'price' => 1
}
@colinodell
53. Protecting Against
SQL Injection
Block input with special
characters
Escape user input
$value = $_REQUEST['value'];
$escaped = mysqli_real_escape_string($value);
$sql = "SELECT * FROM x WHERE y = '$escaped' ";
$database->query($sql);
' OR '1' = '1 ' OR '1' = '1
mysqli_real_escape_string()
SELECT * FROM x WHERE y = '' OR '1' = '1'
54. Protecting Against
SQL Injection
Block input with special
characters
Escape user input
$value = $_REQUEST['value'];
$escaped = mysqli_real_escape_string($value);
$sql = "SELECT * FROM x WHERE y = '$escaped' ";
$database->query($sql);
' OR '1' = '1 ' OR '1' = '1
mysqli_real_escape_string()
SELECT * FROM x WHERE y = '' OR '1' = '1'
55. Protecting Against
SQL Injection
Block input with special
characters
Escape user input
Use prepared statements
$mysqli = new mysqli("localhost", "user", "pass", "db");
$q = $mysqli->prepare("SELECT * FROM x WHERE y = '?' ");
$q->bind_param(1, $_REQUEST['value']);
$q->execute();
Native PHP:
● mysqli
● pdo_mysql
Frameworks / Libraries:
● Doctrine
● Eloquent
● Zend_Db
56. Other Types of Injection
NoSQL databases
OS Commands
LDAP Queries
SMTP Headers
@colinodell
57. XSS
Cross-Site Scripting
Injecting code into the webpage
(for other users)
• Execute malicious scripts
• Hijack sessions
• Install malware
• Deface websites
58. XSS Attack
Basics $value = $_POST['value'];
$value = $rssFeed->first->title;
$value = db_fetch('SELECT value FROM table');
<?php echo $value ?>
Raw code/script
is injected onto a page
59. XSS – Cross-Site Scripting Basics
Snipicons by Snip Master licensed under CC BY-NC 3.0.
Cookie icon by Daniele De Santis licensed under CC BY 3.0.
Hat image from http://www.yourdreamblog.com/wp-content/uploads/2013/04/blackhat.png
Logos are copyright of their respective owners.
<form id="evilform"
action="https://facebook.com/password.php"
method="post">
<input type="password" value="hacked123">
</form>
<script>
document.getElementById('evilform').submit();
</script>
@colinodell
60. XSS – Cross-Site Scripting
short.ly
Paste a URL here Shorten
@colinodell
65. XSS – Cross-Site Scripting
short.ly
<script>alert('hello world!');</script> Shorten
Short URL: http://short.ly/3bs8a
Original URL:
hello world!
OK
X
@colinodell
66. XSS – Cross-Site Scripting
short.ly
<script>alert('hello world!');</script> Shorten
Short URL: http://short.ly/3bs8a
Original URL:
@colinodell
72. Protecting Against
XSS Attacks
$value = $_POST['value'];
$value = db_fetch('SELECT value FROM table');
$value = $rssFeed->first->title;
<?php echo $value ?>
73. Protecting Against
XSS Attacks
• Filter user input
$value = strip_tags($_POST['value']);
$value = strip_tags(
db_fetch('SELECT value FROM table')
);
$value = strip_tags($rssFeed->first->title);
<?php echo $value ?>
74. Protecting Against
XSS Attacks
• Filter user input
• Escape user input
$value = htmlspecialchars($_POST['value']);
$value = htmlspecialchars(
db_fetch('SELECT value FROM table')
);
$value = htmlspecialchars($rssFeed->first->title);
<?php echo $value ?>
<script> <script>
htmlspecialchars()
75. Protecting Against
XSS Attacks
• Filter user input
• Escape user input
• Escape output
$value = $_POST['value'];
$value = db_fetch('SELECT value FROM table');
$value = $rssFeed->first->title;
<?php echo htmlspecialchars($value) ?>
76. Protecting Against
XSS Attacks
• Filter user input
• Escape user input
• Escape output
{{ some_variable }}
{{ some_variable|raw }}
77. CSRF
Cross-Site Request Forgery
Execute unwanted actions on
another site which user is logged in
to.
• Change password
• Transfer funds
• Anything the user can do
78. CSRF – Cross-Site Request Forgery
Hi Facebook! I am
colinodell and my
password is *****.
Welcome Colin!
Here’s your
news feed.
Snipicons by Snip Master licensed under CC BY-NC 3.0.
Cookie icon by Daniele De Santis licensed under CC BY 3.0.
Hat image from http://www.yourdreamblog.com/wp-content/uploads/2013/04/blackhat.png
Logos are copyright of their respective owners.
@colinodell
79. CSRF – Cross-Site Request Forgery
Hi other website!
Show me your
homepage.
Sure, here you go!
Snipicons by Snip Master licensed under CC BY-NC 3.0.
Cookie icon by Daniele De Santis licensed under CC BY 3.0.
Hat image from http://www.yourdreamblog.com/wp-content/uploads/2013/04/blackhat.png
Logos are copyright of their respective owners.
<form id="evilform"
action="https://facebook.com/password.php"
method="post">
<input type="password" value="hacked123">
</form>
<script>
document.getElementById('evilform').submit();
</script>
@colinodell
81. CSRF – Cross-Site Request Forgery
<form id="evilform"
action="https://facebook.com/password.php"
method="post">
<input type="password" value="hacked123">
</form>
<script>
document.getElementById('evilform').submit();
</script>
Tell Facebook we want to
change our password to
hacked123
Snipicons by Snip Master licensed under CC BY-NC 3.0.
Cookie icon by Daniele De Santis licensed under CC BY 3.0.
Hat image from http://www.yourdreamblog.com/wp-content/uploads/2013/04/blackhat.png
Logos are copyright of their respective owners.
@colinodell
82. CSRF – Cross-Site Request Forgery
<form id="evilform"
action="https://facebook.com/password.php"
method="post">
<input type="password" value="hacked123">
</form>
<script>
document.getElementById('evilform').submit();
</script>
Hi Facebook! Please
change my password
to hacked123.
Snipicons by Snip Master licensed under CC BY-NC 3.0.
Cookie icon by Daniele De Santis licensed under CC BY 3.0.
Hat image from http://www.yourdreamblog.com/wp-content/uploads/2013/04/blackhat.png
Logos are copyright of their respective owners.
Done!
@colinodell
86. Protecting Against
CSRF Attacks
Only use POST requests?
NO!
POST requests are vulnerable too
Common Misconceptions:
“<img> tags can only make GET requests”
“If a user doesn’t click a form it won’t submit”
89. Protecting Against
CSRF Attacks
Only use POST requests?
Use a secret cookie?
Use random CSRF tokens
YES!
<input type="hidden" name="token"
value="ao3i4yw90sae8rhsdrf">
1. Generate a random string per user.
2. Store it in their session.
3. Add to form as hidden field.
4. Compare submitted value to session
1. Same token? Proceed.
2. Different/missing? Reject the request.
97. Protecting Against
Insecure Direct
Object References
Check permission on
data input
• URL / route parameters
• Form field inputs
• Basically anything that’s an ID
• If they don’t have permission,
show a 403 (or 404) page
98. Protecting Against
Insecure Direct
Object References
Check permission on
data input
Check permission on
data output
• Do they have permission to
access this object?
• Do they have permission to
even know this exists?
• This is not “security through
obscurity”
106. Private information that is stored, transmitted, or backed-up in
clear text (or with weak encryption)
• Customer information
• Credit card numbers
• Credentials
Sensitive Data Exposure @colinodell
107. Security Misconfiguration & Components with Known Vulnerabilities
Default accounts enabled; weak passwords
• admin / admin
Security configuration
• Does SSH grant root access?
• Are weak encryption keys used?
Out-of-date software
• Old versions with known issues
• Are the versions exposed?
• Unused software running (DROWN attack)
@colinodell
111. Protecting Against
Sensitive Data Exposure, Security
Mismanagement, and
Components with Known
Vulnerabilities
Keep software up-to-date
• Install critical updates immediately
• Install other updates regularly
112. Protecting Against
Sensitive Data Exposure, Security
Misconfiguration, and
Components with Known
Vulnerabilities
Keep software up-to-date
Keep sensitive data out
of web root
• Files which provide version numbers
• README, CHANGELOG, .git, composer.lock
• Database credentials & API keys
• Encryption keys
113. Protecting Against
Sensitive Data Exposure, Security
Misconfiguration, and
Components with Known
Vulnerabilities
Keep software up-to-date
Keep sensitive data out
of web root
Use strong encryption
• Encrypt with a strong private key
• Encrypt backups and data-in-transit
• Use strong hashing techniques for
passwords
114. Protecting Against
Sensitive Data Exposure, Security
Mismanagement, and
Components with Known
Vulnerabilities
Keep software up-to-date
Keep sensitive data out
of web root
Use strong encryption
Test your systems
• Scan your systems with automated
tools
• Test critical components yourself
• Automated tests
• Manual tests
115. Next Steps
Test your own applications for vulnerabilities
Learn more about security & ethical hacking
Enter security competitions (like CtF)
Stay informed
@colinodell
14 years
Capture the Flag is
Not a professional security researcher, but
I’d like to share some of that knowledge with you today
“Goals of this intermediate-level talk”
“Asking forgiveness is easier than asking for permission”
Not if you’re in jail
----
I might mention some real sites, but none are actually vulnerable
Just make it easier to explain things since you’re probably familiar with how they’re supposed to function
Non-profit organization
Provide free articles, resources, and tools for web security
Each risk is documented with a description, detailed examples, mitigation techniques, and references to other helpful resources
[Quickly]
Syntax error
Single quote is missing its pair
Query is structured differently than expected
Table or column doesn’t exist
If we know site is vulnerable and see this (#2)
SQL injection almost worked
Table and column names are valid
Assertion failed
SQL injection worked (definitely)
Database and column names are valid
Assertion succeeded or conditional bypassed
Let’s try to figure out table and column names
Probably a user table
But previous method is all guesswork
What if… just show the data?
OUTRO: So that’s the desired functionality
But what if this site was vulnerable?
What could we do?
Well…
Maybe we could somehow set the id to cause a SQL injection that ouputs other information we want.
But how you ask?
With the SQL UNION operator…
CLICK TO ANIMATE EXPLANATION
OUTRO: Or better yet…
CLICK TO ANIMATE EXPLANATION
OUTRO: Or better yet…
So when the server sends the code,
The browser runs it as-is
Just like all other HTML/JS that intentionally runs
(EXPLAIN CODE)
This JS should create an alert popup window
(SUBMIT)
AUDIO STARTS NEXT SLIDE
Ex 1: REDDIT
Ex 2: phpbb forums
Some data loss
Pastebin, Gist, etc
Safer, no data loss
Laravel blade – also automatic, similar syntax
OUTRO: Can also be done by using XSS
[Cross site request forgery]
What if we…
Would that be safe?
This is one of many common misconceptions some developers have.
For example…
Hidden value, only shown on our website, that only us and the current page know
OTHER SITES CANT SEE THIS VALUE, ONLY THE USER (due to browser’s same-origin policy)
NOT SAVED TO COOKIE OR AVAILABLE OUTSIDE WEBSITE!
(AFTER BULLETS)
Remember, the attacker doesn’t have access to their session or the HTML you generated dynamically for the particular user.
Let’s imagine Facebook is vulnerable to [READ TITLE]
Just change the 9 to an 8…
Even though Facebook never linked us here, we still got here
And FB didn’t check again at _this_ point in time
OUTRO: Fake example – FB doesn’t do this…
Facebook does check whether you’re authorized to see the image
OUTRO: Not just limited to URLs…
If bank is vulnerable, and form is submitted,
They won’t check the ID and allow the transfer to go through
Bad!
#2 – I like Symfony because it whitelists values in values in dropdowns (…)
#3 – Good guideline, but not all-encompassing rule
#3 – That means hiding the objects / IDs as the only measure of security
What I mean is not disclosing information users shouldn’t see, or showing actions they can’t take
Actually three different vuln
Similar enough
Is private data being exposed to the world?
OUTRO:
So that’s sensitive data exposure.
In a similar vein we have…
[DROWN: fast description]
You might be thinking OMG they explain the attack?
Yes, but it’s a good thing!
Problem is: your version is exposed, hackers may know you’re vulnerable
#1 – If there’s a patch available, there’s also a hacker who can understand the original problem and create an exploit
#2 – Otherwise software falls into decay and is extremely hard to upgrade when the next critical update rolls out
END: But really, you should hide them
Good advice in general for all security topics we’ve covered
And that wraps up the last set of vulenerabilities we’re covering today