Skip to content

Commit

Permalink
Open source release
Browse files Browse the repository at this point in the history
  • Loading branch information
DCKcode committed May 19, 2021
0 parents commit 82b8dce
Show file tree
Hide file tree
Showing 32 changed files with 2,583 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Release

on:
push:
branches:
- 'main'

jobs:
release:
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2
- name: Set up JDK 15
uses: actions/setup-java@v2
with:
java-version: '15'
distribution: 'adopt'
- name: Run unit tests
run: ./gradlew test
- name: Build release
run: ./gradlew -Prelease fatJar
- name: Get current timestamp for release
id: date
run: echo "::set-output name=date::$(date --utc +'%Y-%m-%d')"
- name: Publish release
uses: ncipollo/release-action@v1
with:
artifacts: build/libs/1PasswordSessionAnalyzerForBurp-main-*.jar
omitBody: true
omitName: true
tag: release-${{ steps.date.outputs.date }}
token: ${{ secrets.GITHUB_TOKEN }}
20 changes: 20 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Test

on:
push:
branches:
- '!master'

jobs:
test:
runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2
- name: Set up JDK 15
uses: actions/setup-java@v2
with:
java-version: '15'
distribution: 'adopt'
- name: Run unit tests
run: ./gradlew test
62 changes: 62 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,intellij,vscode
# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,intellij,vscode

### InteliJ
.idea/
out/
.idea_modules/

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

### vscode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace

### Gradle ###
.gradle
build/

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Cache of project
.gradletasknamecache

# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties

### Gradle Patch ###
**/build/

# End of https://www.toptal.com/developers/gitignore/api/java,gradle,intellij,vscode
27 changes: 27 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright (c) MMXXI, AgileBits Inc
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

- Neither the name of Thomas J Bradley nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 1Password session analyzer plugin for Burp Suite

This repository contains a [Burp](https://portswigger.net/burp) plugin that adds a special message editor view to Burp to analyze and edit requests made to 1Password.com.

## What is this for?

As we say in our [bounty brief](https://bugcrowd.com/agilebits), 1Password is not your regular web application. The first time security researchers open their HTTP proxy of choice when testing 1Password.com, they soon notice that this does not look like a regular web app at all. Rather than regular HTML or JSON, the server returns opaque blobs of content. When the 1Password.com web app sends a payload to the server, it is also an opaque blob, and any request you tamper with in the slightest returns an error.

This behavior is the result of the security features of 1Password.com. We require every request and response that are specific to a 1Password account to be protected by the account's master password and secret key, which means every bit of data that gets sent is encrypted, and every request is authenticated.

### Nice, but this makes bug hunting really hard!
It does! Using common tools to find security bugs on web applications really does not work well on 1Password.com. If you want to do any sort of legitimate inspection of 1Password.com - while fully knowing the master password and secret key for your account - you'll need some extra tools.

In order to make bug hunting with 1Password.com a lot easier, we are publishing this Burp plugin to help you analyze and modify requests sent between the 1Password.com web application and server as long as you have a valid session key. The next section dives into how session management with 1Password.com works.

### Encrypting payloads
At 1Password we want to make one thing very sure: no one should be able to access your data, without your master password and secret key. That applies to the vault data stored on your computer or phone, and to the data that we store on our servers. It also applies to any network infrastructure that sits between you and the 1Password servers. Proxy servers sitting between you and 1Password.com should not be able to see what you do with your 1Password account, even if they manage to break TLS.

Therefore, when you log in to 1Password.com or any of the 1Password apps, we use a Password Authenticated Key Exchange (PAKE) to derive what we call a session key. At this time, we use a modified version of the Secure Remote Password Protocol (SRP) as our PAKE. This derived session key is used to add an additional layer of encryption on top of the TLS we use for all requests.

Our APIs are all JSON-based, and all JSON payloads are encrypted using (at the time of writing) an AES256 GCM based cipher. This is wrapped in another JSON payload, which are the blobs being sent to and received from 1Password.com. Since the session key derives directly from your master password and secret key, having access to the session key is the equivalent to knowing your master password and secret key.

![Session management overview](docs/images/session_management.svg)

### Authenticating requests
Once you are able to successfully encrypt and decrypt messages with the session key, you'll soon notice that whenever you modify your message the server still rejects your requests. What is going on?

There is a separate mechanism protecting requests, the request MAC. Every request 1Password clients send to the server includes a request header named X-Agilebits-Request-MAC, which is of the form `v1|25|8MPu848dH2kKdVRa`. The three components of this request MAC are a version indicator (always v1 right now), an incrementing request identifier and 12 bytes encoded as base64 that is a truncated message authentication code.

The request MAC ensures that certain properties of the request can only be generated by a client. Since the request MAC stores a counter of which request was made to the server, which the server verifies, it prevents replaying encrypted messages. As an aside, this also categorically prevents cross site request forgery, as making any request to your account requires some access to the session key locally.

The request MAC value is derived using the following process:
```
authString := sessionId || "|" || requestMethod || "|" || url || versionIndicator || requestId
derivationKey := HMAC(sessionKey, "He never wears a Mac, in the pouring rain. Very strange.")
mac := HMAC(authString, derivationKey)
headerValue := base64url(mac[0:12])
```
The HMAC algorithm currently used for v1 is HMAC-SHA256.

## Using this plugin

The Burp plugin works with Burp's message editor and contains its own custom implementation of 1Password.com's session management protocol. You activate it by loading the JAR file in Burp's extender tab, like any other Burp plugin.

When activated, it provides a number of inputs, such as an input for the original HTTP message, and an input for the decrypted payload (if present). It also provides a way to edit the request identifier, the key identifier and the session key itself. Inputting the correct session key will automatically decrypt the message and allow you to inspect and modify payloads and requests.

**Please note:** The Burp plugin contains automatic detection of 1Password session data. It's only available on sessions with 1Password.com, and cannot be activated on sessions that don't contain 1Password session data.

![Example screenshot of the plugin](docs/images/example_screenshot.png)

Since this Burp plugin is for the Burp message editor, it can be used only in the following places in Burp:

* Proxy -> Intercept
* Proxy -> HTTP history
* Repeater

### How do I obtain the session key?
You might wonder how you obtain the session key from your session on 1Password.com. Here we are going to ask you to do a little homework yourself. You will probably understand we can not provide a stable way of getting access to your own session key, but you can probably find the session key yourself by knowing that we use [standard JavaScript APIs](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) to do the encryption in the 1Password frontend.

## How to build yourself

Make sure you to install Java 15 on your computer. On a Mac with Homebrew, run:
```shell
brew tap AdoptOpenJDK/openjdk
brew install adoptopenjdk15
```

`./gradlew fatJar` builds this plugin and puts the resulting JAR file in `build/libs`.

## How to debug
To be able to connect a Java debugger to your Burp plugin, you must manually start Burp from your command line. On a Mac, run:

```sh
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address='*:5005' -jar /Applications/Burp\ Suite\ Community\ Edition.app/Contents/java/app/burpsuite_community.jar
```

You can now connect your debugger on local port 5005. For example, in IntelliJ IDEA you can add a _Remote JVM debugger_ configuration with the following command line configured: `-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005`

## How to test
Run the tests using `./gradlew test`. The test output results are in `build/test-results`.
44 changes: 44 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
plugins {
id 'java'
id 'net.nemerosa.versioning' version '2.14.0'
}

group 'com.1password.burp-analyzer'

repositories {
mavenCentral()
}

dependencies {
compile 'net.portswigger.burp.extender:burp-extender-api:2.1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.12.3'
compile 'com.fifesoft:rsyntaxtextarea:3.1.2'
compile 'io.vavr:vavr:0.10.3'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

versioning {
ext.makeVersion = {
if (project.hasProperty('release')) {
def dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd")
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"))
def today = dateFormat.format(new Date())
return String.format("%s-%s", versioning.info.full, today)
} else {
return "dev"
}
}
}

version versioning.ext.makeVersion()

task fatJar(type: Jar) {
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
}

test {
useJUnit()
}
Binary file added docs/images/example_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/images/session_management.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit 82b8dce

Please sign in to comment.