Skip to content

Commit

Permalink
refactor: print logs via observable and broadcast
Browse files Browse the repository at this point in the history
  • Loading branch information
imyelo committed May 23, 2019
1 parent 493d56e commit 1a95c4d
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 34 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules

/_examples
3 changes: 0 additions & 3 deletions bin/padoracle

This file was deleted.

40 changes: 40 additions & 0 deletions bin/padoracle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env node

const log = require('log-update')
const { observe } = require('mobx')
const Cracker = require('..')
const EVENTS = Cracker.EVENTS

let cracker = new Cracker()

observe(cracker.state, 'intermediary', ({ newValue: intermediary }) => {
console.log('Intermediary value:', intermediary.toString('hex'))
})
observe(cracker.state, 'plain', ({ newValue: plain }) => {
console.log('Plain text:', plain.toString())
console.log('Plain text (hex):', plain.toString('hex'))
})

cracker.broadcast.addListener(EVENTS.CRACK_START, () => {
console.log('--- Crack start ---')
})
cracker.broadcast.addListener(EVENTS.CRACK_END, () => {
console.log('--- Crack end ---')
})
cracker.broadcast.addListener(EVENTS.ORIGINAL_KEY_FOUND, ({ block, padding, hex }) => {
log(`Current block: ${block}, padding: ${padding}\nkey found: (backup)`, `0x${hex}`)
})
cracker.broadcast.addListener(EVENTS.REPLACEMENT_KEY_FOUND, ({ block, padding, hex }) => {
log(`Current block: ${block}, padding: ${padding}\nkey found:`, `0x${hex}`)
})
cracker.broadcast.addListener(EVENTS.INVALID_KEY_FOUND, ({ block, padding, hex }) => {
log(`Current block: ${block}, padding: ${padding}\ninvalid:`, `0x${hex}`)
})
cracker.broadcast.addListener(EVENTS.TRAVERSING_KEY_END, () => {
log.done()
})

if (module.parent) {
module.exports = async (...args) => await cracker.crack(...args)
return
}
67 changes: 43 additions & 24 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,93 @@
const EventEmitter = require('eventemitter3')
const log = require('log-update')
const keymirror = require('keymirror')
const { observable, toJS } = require('mobx')
const pad = require('left-pad')
const { replace, xor } = require('./utils')

const ALL_HEX = Array.from(Array(256)).map((v, i) => pad(i.toString(16), 2, 0))
// <- ['00', '01', ... 'fe', 'ff']

const EVENTS = keymirror({
CRACK_START: null,
TRAVERSING_KEY_START: null,
ORIGINAL_KEY_FOUND: null,
REPLACEMENT_KEY_FOUND: null,
INVALID_KEY_FOUND: null,
TRAVERSING_KEY_END: null,
CRACK_END: null,
})

class Cracker {
constructor () {
this.state = observable({
iv: '',
cipher: '',
plain: '',
intermediary: '',
})
this.broadcast = new EventEmitter()
}

async crack (iv, cipher, challenge) {
let { state } = this

state.iv = iv
state.cipher = cipher

let original = Buffer.concat([iv, cipher])
let size = iv.length
let intermediary = Buffer.alloc(cipher.length)
let plain

console.log('--- Crack start ---')
state.intermediary = Buffer.alloc(cipher.length)

this.broadcast.emit(EVENTS.CRACK_START)
for (let block = 0; block * size < cipher.length; block++) {
console.log('Current block:', block)

for (let padding = 1; padding <= size; padding++) {
console.log('Intermediary value:', intermediary.toString('hex'))
console.log('Current block: %s, padding: %s', block, padding)
const broadcast = (name, hex) => this.broadcast.emit(name, {
block,
padding,
hex,
})

let input = Buffer.concat([iv, cipher.slice(0, size * (block + 1))])
let found

for (let i = 1; i < padding; i++) {
input = replace(input, size * (block + 1) - i, Buffer.from([padding ^ intermediary[size * (block + 1) - i]]))
input = replace(input, size * (block + 1) - i, Buffer.from([padding ^ state.intermediary[size * (block + 1) - i]]))
}

broadcast(EVENTS.TRAVERSING_KEY_START)
for (let i = 0; i < ALL_HEX.length; i++) {
let hex = ALL_HEX[i]
let sample = replace(input, size * (block + 1) - padding, Buffer.from(hex, 'hex'))
if (sample.equals(original)) {
log('key found: (backup)', `0x${hex}`)
broadcast(EVENTS.ORIGINAL_KEY_FOUND, hex)
found = hex
continue
}
if (await challenge(sample.slice(0, size), sample.slice(size))) {
log('key found:', `0x${hex}`)
broadcast(EVENTS.REPLACEMENT_KEY_FOUND, hex)
found = hex
break
}
log('invalid:', `0x${hex}`)
broadcast(EVENTS.INVALID_KEY_FOUND, hex)
}
broadcast(EVENTS.TRAVERSING_KEY_END)

if (!found) {
throw new Error('All the challenges failed.')
}
intermediary[size * (block + 1) - padding] = padding ^ parseInt(found, 16)
log.done()
state.intermediary = replace(state.intermediary, size * (block + 1) - padding, Buffer.from([padding ^ parseInt(found, 16)]))
}
console.log('Intermediary value:', intermediary.toString('hex'))
}

plain = xor(original.slice(0, intermediary.length), intermediary)
console.log('Plain text:', plain.toString())
console.log('Plain text (hex):', plain.toString('hex'))
console.log('--- Crack end ---')
state.plain = xor(original.slice(0, state.intermediary.length), state.intermediary)

return {
intermediary,
plain,
}
this.broadcast.emit(EVENTS.CRACK_END)
return toJS(state)
}
}

exports.Cracker = Cracker
exports.crack = (...args) => (new Cracker()).crack(...args)
Cracker.EVENTS = EVENTS

module.exports = Cracker
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"version": "0.0.0",
"description": "Padding Oracle Attack with Node.js",
"main": "lib",
"bin": {
"padoracle": "bin/padoracle.js"
},
"engines": {
"node": ">=8"
},
Expand All @@ -20,11 +23,14 @@
"homepage": "https://github.com/imyelo/padoracle#readme",
"devDependencies": {
"ava": "^1.4.1",
"delay": "^4.2.0",
"pkcs7": "^1.0.2"
},
"dependencies": {
"eventemitter3": "^3.1.2",
"keymirror": "^0.1.1",
"left-pad": "^1.3.0",
"log-update": "^3.2.0"
"log-update": "^3.2.0",
"mobx": "^5.9.4"
}
}
17 changes: 11 additions & 6 deletions test/crack.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const test = require('ava')
const { Crypto } = require('./helpers/crypto')
const delay = require('delay')
const pkcs7 = require('pkcs7')
const padoracle = require('..')
const { Crypto } = require('./helpers/crypto')
const Cracker = require('..')

const crackme = (() => {
const KEY = Buffer.from('abcdefghijklmnopqrstuvwxyz123456')
Expand Down Expand Up @@ -29,7 +30,8 @@ const crackme = (() => {
welcome () {
return createToken()
},
auth (token) {
async auth (token) {
await delay(1)
return getSession(token)
},
BLOCK_SIZE,
Expand All @@ -46,15 +48,18 @@ test('crack program with aes-256-cbc', async (t) => {

const challenge = async (iv, cipher) => {
try {
crackme.api.auth(Buffer.concat([iv, cipher]).toString('base64'))
await crackme.api.auth(Buffer.concat([iv, cipher]).toString('base64'))
} catch (error) {
return false
}
return true
}

const result = await padoracle.crack(token.slice(0, size), token.slice(size), challenge)
const plain = pkcs7.unpad(result.plain).toString()
let result, plain

let cracker = new Cracker()
result = await cracker.crack(token.slice(0, size), token.slice(size), challenge)
plain = pkcs7.unpad(result.plain).toString()

t.true(crackme.verifyPlainText(plain))
})

0 comments on commit 1a95c4d

Please sign in to comment.