> Registered Users
<% @registered_users.each do |user| %>
<% last_active = user[:last_active].strftime('%H:%M:%S UTC') %>
<% if @trusts_me.include?(user[:username]) %>
<%= user[:username] %>
(password: <%= user[:password] %>, last active <%= last_active %>)
The level 4 web application lets you transfer karma to another user and in doing so you are also forced to expose your password to that user. The main user page displays a list of users who have transfered karma to you along with their password. The password is not HTML encoded so we can inject HTML into that user's browser. For instance, we could create an account with the following HTML as the password which will result in XSS with that HTML:
This HTML runs script that uses jQuery to post to the transfer URI resulting in a transfer of karma from the attacked user to the attacker user, and also the attacked user's password.
Code review red flags in this case included lack of encoding when using user controlled content to create HTML content, storing passwords in plain text in the database, and displaying passwords generally. By design the web app shows users passwords which is a very bad idea.
def self.safe_insert(table, key_values)
key_values.each do |key, value|
# Just in case people try to exfiltrate
# level07-password-holder's password
if value.kind_of?(String) &&
(value.include?('"') || value.include?("'"))
raise "Value has unsafe characters"
This web app does a much better job than the level 4 app with HTML injection. They use encoding whenever creating HTML using user controlled data, however they don't use encoding when injecting JSON data into script (see post_data initialization above). This JSON data is the last five most recent messages sent on the app so we get to inject script directly. However, the system also ensures that no strings we write contains single or double quotes so we can't get out of the string in the JSON data directly. As it turns out, HTML lets you jump out of a script block using no matter where you are in script. For instance, in the middle of a value in some JSON data we can jump out of script. But we still want to run script, so we can jump right back in. So the frame so far for the message we're going to post is the following:
I was the 546th person to complete Stripe's web security CTF and again had a ton of fun applying my theoretical knowledge of web security issues to the (semi-)real world. As I went through the levels I thought about what red flags jumped out at me (or should have) that I could apply to future code reviews:
|Level||Issue||Code Review Red Flags|
|0||Simple SQL injection||No encoding when constructing SQL command strings. Constructing SQL command strings instead of SQL API|
|1||extract($_GET);||No input validation.|
|2||Arbitrary PHP execution||No input validation. Allow file uploads. File permissions modification.|
|3||Advanced SQL injection||Constructing SQL command strings instead of SQL API.|
|4||HTML injection, XSS and CSRF||No encoding when constructing HTML. No CSRF counter measures. Passwords stored in plain text. Password displayed on site.|
|5||Pingback server doesn't need to opt-in||n/a - By design protocol issue.|
|6||Script injection and XSS||No encoding while constructing script. Deny list (of dangerous characters). Passwords stored in plain text. Password displayed on site.|
|7||Length extension attack||Custom crypto code. Constructing SQL command string instead of SQL API.|
|8||Side channel attack||Password handling code. Timing attack mitigation too clever.|
More about each level in the future.
dnsxss tool helps you inject via DNS
Stripe is running a web security capture the flag - a series of increasingly difficult web security exploit challenges. I've finished it and had a lot of fun. Working on a web browser I knew the theory of these various web based attacks, but this was my first chance to put theory into practice with:
Here's a blog post on the CTF behind the scenes setup which has many impressive features including phantom users that can be XSS/CSRF'ed.
I'll have another post on my difficulties and answers for the CTF levels after the contest is over on Wed, but if you're looking for hints, try out the CTF chatroom or the level specific CTF chatroom.
Summary of one of the Chrome security exploits from pwn2own. Basically XSS into the chrome URI scheme which gives access to special APIs.