Skip to content

Commit

Permalink
Antihero stories.
Browse files Browse the repository at this point in the history
  • Loading branch information
Zemnmez committed Nov 25, 2024
1 parent 0117e5e commit ddfac0b
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 0 deletions.
198 changes: 198 additions & 0 deletions mdx/article/2024/antihero_stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
title: Antihero Stories
date:
- 22
- nov
- 2024
tags:
- writing
- security
language: en-GB
description: Article where I explain why I think a user story written from the point of view of an attacker should be mandatory.
---

Antihero Stories.
-------------------------------------------------------------------------------

*In this article, I explain why I think it should be *mandatory* for security
vulnerabilities to come with a form of ‘user story’ – a short, first-person
story from the point of view of an attacker and I decry [weasel-word] usage of
technical security terms to create the appearance of vulnerability where there
is none.*

[weasel-word]: https://en.wikipedia.org/wiki/Weasel_word "Weasel word
(Wikipedia)"

In the early days of computer hacking, everything had to happen by destruction
or whining.

In Hackers (1994) 11-year-old Dade “Zero Cool” Murphy’s family is fined $45,000
for his crashing of 1,507 computer systems, causing a seven-point drop in the
New York Stock Exchange. This is destruction. I'm certain the NYSE fixed the
issue within 30 business days.

Hackers (1994) is a fiction. Real hackers mostly had to get by with whining,
which is where I send an email explaining how bad the issue is, pleading to
have it fixed. In a twist of fate I argue is convergent evolution, the best of
these look like [user stories][user story]:

[user story]: https://en.wikipedia.org/wiki/user_story "User story (Wikipedia)"

> (As an attacker,) I want to get access to a victim’s account, so I can divert
> their payout information to my bank account. When I send the victim user my
> special link, it causes their browser to send my server their authorization
> token. I, (as an attacker,) use this token to change the victim's payout
> information.
I think this is the golden standard of describing a vulnerability. The intent
is clear. The means is clear. The impact is clear. Whining is a clear and
concise method of explanation to non-hackers born of necessity.

A vulnerability is a path through a very complex system. Most of those paths go
nowhere. Even ones that fit into vulnerability taxonomies. A hacker puts all
these complex pieces together and – in theory – creates a path through them
that starts at something an attacker can control, and ends in something the
attacker wants.

Thanks to the advent of Bug Bounty and Responsible Disclosure, even to the the
outside world, sometimes all we need to say is ‘XSS’, or ‘SQLi’, ‘open
redirect’, ‘buffer overflow’, or traversing into the barely legitimate:
‘content injection’, ‘information leak’, ‘confused deputy’. Security vendors
will be string these together like novel animal species or viral strains and
season with a smattering of CVSS values based on vibes.

Many of these technical terms came to exist as legitimate shorthand between
comrades who trust each and want to short-cut the explaining. Most hackers know
what `alert(document.origin)` means. Everyone knows what it means to pop a
calculator. These are all shorthands. They do not demostrate the existence of
the paths I mentioned before.

I do genuinely think that our usage of this type of security terminology has,
in the hands of some, taken on a distinctly dark and insincere bent that I
think that user stories could dispel. I will follow this with an example I came
across that I think illustrates this well, but before that, let’s analyse some
terms I particularly dislike.

“Broken”, “Missing”, and “Improper”.
===============================================================================

Vulnerability taxonomies exist to categorise vulnerabilities for tracking. But
they are irrevocably tied to the idea that demonstrating a category of taxonomy
inherently demonstrates vulnerability. In this sense, Everything in the
[Bugcrowd Vulnerability Taxonomy] that includes ‘broken’ is on my shitlist.
This includes: **Broken Authentication and Session Management**, **Broken
Access Control (BAC)**, **Broken Access Control (BAC)**, and **Broken
Cryptography**.

[Bugcrowd Vulnerability Taxonomy]:
https://bugcrowd.com/vulnerability-rating-taxonomy

I also include the more standard CWE terms “missing”, and “improper” when it is
presented without reference to a specific technology: [CWE-862] “Missing
Authorization”, [CWE-20] “Improper Input Validation”, [CWE-287] “Improper
Authentication”, [CWE-269] “Improper Privilege Management”, and so on.

[CWE-862]: https://cwe.mitre.org/data/definitions/862.html
[CWE-20]: https://cwe.mitre.org/data/definitions/20.html
[CWE-297]: https://cwe.mitre.org/data/definitions/287.html
[CWE-269]: https://cwe.mitre.org/data/definitions/269.html

These terms fulfil only the function of telling the reader that the reporter
thinks the thing in question is bad, without any information at all about why
it is bad. *Of course* the reporter thinks the thing is bad. They would not be
reporting it otherwise.

It is eminently obvious that demonstration of ‘Missing Authorization’ is not
itself a demonstration of a security vulnerability. Nobody should be making
arguments that being able to access ChatGPT without being logged in is a
vulnerability. The term _begs the question_ of _why_ the reporter thinks
missing authorization is an issue.

If I asked them why it was an issue, perhaps they would say ‘unauthorized
access to customer data’ – in which case, congratulations! We've found an
actually good way of describing the vulnerability at hand.

I think in a way, this is a reflection of the ‘[five whys]’ principle. The
answer to ‘why did we have an incident yesterday’ should not be ‘the website
was down’. It should be ‘we do not prevent two commits being deployed to
production at the same time’ or some other statement reflecting a resolution
that cuts deep enough to not have to ask ‘why?’ one more time.

[five whys]: https://en.wikipedia.org/wiki/Five_whys "Wikipedia: Five whys"





Thomas

San Francisco, California, USA

Below are segments from the old article! They should be re-incorperated where
appropritate:

Data URI Injection This was a craaazy vulnerability type between probably
sometime in the 90s until about 2017. When you use the web, you're on 'http:'.
That's the protocol. But there's also 'mailto:' for email, and there once was
'ftp:' for file transfer. After Web 2.0 became a thing, data: URIs became a
thing. Normally, if I put a picture such as below, a beautiful picture of San
Francisco's Civic Centre plaza in 1940, it is a link (like with 'http:') loaded
off the internet. So your browser goes to that link for you that has the
picture, downloads it, and puts it in the page. But that means loading 2
 things, and it's 2010 and loads are slow! Ray M. Mann, Jr. Color Slides of
Golden Gate International Exposition, 1940. SFPL AAZ-1445So when I put this
other picture of the same location in 2024 in my web page, I may use a data:
URI. And this data: URI might specify the full content of the image in-line,
without a second request being made. That way, you can see the tragic extent of
the demolition of San Francisco's civic space much more quickly. Google
Street ViewI can't put one here in Medium, because they're banned. Why are they
banned? Because until 2017, a data: URI was considered a fully trusted part of
the page it appeared in, and that meant security issues. Sure, it was most
often used for images, like this 1907 photo of the gardens surrounding San
Francisco's Pioneer Monument: Pioneer Monument in Civic Center, San Francisco
Department of Public Works (San Francisco, Calif.) 1907–1920 SFPL DPW-4794But
it could be used to also specify web pages, such as
data:text/html,`<script>alert(document.domain)</script>` . This web page is a
tiny little one, and it contains a single piece of code. That little piece of
code makes a pop-up on the screen saying what the web browser thinks the
security identity of the page is. In 2010, a link like that on Medium.com would
cause a pop-up window saying 'medium.com'. This meant that the mere action of
making a link resulted in an attacker being able to inject code into the page!
In other words: As an attacker, I want to delete your Medium posts, because
they're not good. I make my own Medium post and in the first paragraph I make a
prominent link along the lines of: "first, please note the required watching"
When my victim (you) clicks this link, my injected code runs. The browser
believes that my injected code comes from Medium.com, and the code directs your
browser to act as though you clicked 'delete' on your article. Your article is
deleted. But by 2017, browser vendors realised data: URIs being treated like
they were blessed by the page where the link was present was a really bad idea.
They made it so that these links are treated by the browser as though they are
in an opaque origin, a kind of shadow realm that unsafe code is sent to where
it may not be blessed with the gift of knowing its own origin. In a modern
browser, clicking a data: URI with my code results in a single word null ,
which is the human name for the opaque origin. This hasn't stopped people
claiming it's a security issue though! They just removed the document.domain
proof that the origin is inherited and instead the pop-up just says "XSS!". A
quick Google shows payouts on HackerOne for this as late as 2020 using exactly
this sleight of hand (by 2021, it looks like people had caught on). I remember
responding to these for years. I don't think these payouts were from
well-informed individuals making carefully considered decisions about their
long-tail of users who haven't upgraded their web browsers since 2017. The
first XSS of this kind I'm sure had to justify itself; but by 2020 we were
happy to fork over $500 at the first sign of a pop-up, having totally forgotten
what the meaning of the action was. By the way, this is what the Pioneer
Monument looks like today: Google MapsCall to Action I am not saying that user
stories are bulletproof. A malicious reporter absolutely could concoct a user
story that appears true, but is not. But the difference is the currency. The
fact is, what the reporter demonstrated was XSS. They have presented valid
currency in the system we have built. But the real currency is risk, and that's
a product of probability and impact, something expressed intuitively in a user
story. I think if we more often did, we would be much easier to understand. I
want to live in a world where someone mostly non-technical can read a security
vendor report and intuitively understand why 'network-local hypertext
information leak sidechannel' was rated CVSS 3.0 4.7 (Medium)
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N. I don't think it's too far away.
I promise, you can still send your reports in PDFs 0.5–1 vulnerabilities to a
piece of paper. With cover sheets for each section, and some pages
intentionally left blank. I'll leave a few SSL cipher suites a few years out of
date as a treat.
20 changes: 20 additions & 0 deletions project/zemn.me/app/article/2024/antihero_stories/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
load("//bzl:rules.bzl", "bazel_lint")
load("//ts:rules.bzl", "ts_project")

ts_project(
name = "antihero_stories",
assets = glob(["**/*.css"]),
visibility = ["//project/zemn.me:__subpackages__"],
deps = [
"//:node_modules/next",
"//mdx:mdx_js",
"//project/zemn.me/components/Article",
"//ts/react/lang",
"//ts/time",
],
)

bazel_lint(
name = "bazel_lint",
srcs = ["BUILD.bazel"],
)
17 changes: 17 additions & 0 deletions project/zemn.me/app/article/2024/antihero_stories/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import { Metadata } from 'next/types';

import Content from '#root/mdx/article/2024/antihero_stories.js'
import { frontmatter } from '#root/mdx/article/2024/antihero_stories.js';
import { articleMetadata } from '#root/project/zemn.me/components/Article/article_metadata.js';
import { MDXArticle } from '#root/project/zemn.me/components/Article/mdx_article.js';



export default function Page() {
return <MDXArticle {...{frontmatter}}>
<Content/>
</MDXArticle>
}

export const metadata: Metadata = articleMetadata(frontmatter);
1 change: 1 addition & 0 deletions project/zemn.me/app/article/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ts_project(
deps = [
"//project/zemn.me/app/article/2014/csp",
"//project/zemn.me/app/article/2019/cors",
"//project/zemn.me/app/article/2024/antihero_stories",
"//project/zemn.me/app/article/2024/missing",
],
)
Expand Down

0 comments on commit ddfac0b

Please sign in to comment.