{"id":18265866,"url":"https://github.com/mpgn/padding-oracle-attack","last_synced_at":"2025-04-06T16:15:53.647Z","repository":{"id":47764240,"uuid":"49711754","full_name":"mpgn/Padding-oracle-attack","owner":"mpgn","description":":unlock: Padding oracle attack against PKCS7 :unlock:","archived":false,"fork":false,"pushed_at":"2022-10-05T07:30:43.000Z","size":37,"stargazers_count":329,"open_issues_count":3,"forks_count":58,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-30T15:09:46.317Z","etag":null,"topics":["attack","cbc-mode","oracle","padding","padding-error"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpgn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["mpgn"]}},"created_at":"2016-01-15T10:13:24.000Z","updated_at":"2025-03-29T16:58:40.000Z","dependencies_parsed_at":"2023-01-19T06:15:36.525Z","dependency_job_id":null,"html_url":"https://github.com/mpgn/Padding-oracle-attack","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FPadding-oracle-attack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FPadding-oracle-attack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FPadding-oracle-attack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpgn%2FPadding-oracle-attack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpgn","download_url":"https://codeload.github.com/mpgn/Padding-oracle-attack/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247509238,"owners_count":20950232,"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":["attack","cbc-mode","oracle","padding","padding-error"],"created_at":"2024-11-05T11:20:13.249Z","updated_at":"2025-04-06T16:15:53.629Z","avatar_url":"https://github.com/mpgn.png","language":"Python","funding_links":["https://github.com/sponsors/mpgn"],"categories":[],"sub_categories":[],"readme":"# Padding Oracle Attack\r\n\r\nAn exploit for the [Padding Oracle Attack](https://en.wikipedia.org/wiki/Padding_oracle_attack). Tested against ASP.NET, works like a charm. The CBC  mode must use [PKCS7](https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7) for the padding block.\r\nThis is an implementation of this great article [Padding Oracle Attack](https://not.burntout.org/blog/Padding_Oracle_Attack/). Since the article is not very well formated and maybe unclear, I made an explanation in the readme. I advise you to read it if you want to understand the basics of the attack.\r\nThis exploit allows block sizes of 8 or 16. This means it can be used if the cipher uses AES or DES. You can find instructions to launch the attack [here](https://github.com/mpgn/Padding-Oracle-Attack#options).\r\n\r\nI also made a test file `test.py`, you don't need a target to use it :)\r\n\r\n## Explanation\r\n\r\nI will explain in this part the cryptography behind the attack. To follow this you need to understand the [CBC mode cipher chainning](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29) or [video link](https://www.youtube.com/watch?v=0D7OwYp6ZEc.) and the operator ⊕. This attack is also a [chosen-ciphertext attack](https://en.wikipedia.org/wiki/Chosen-ciphertext_attack).\r\n\r\nEncryption | Decryption\r\n--- | --- \r\nC\u003csub\u003ei\u003c/sub\u003e = E\u003csub\u003ek\u003c/sub\u003e(P\u003csub\u003ei\u003c/sub\u003e ⊕ C\u003csub\u003ei-1\u003c/sub\u003e), and C\u003csub\u003e0\u003c/sub\u003e = IV | P\u003csub\u003ei\u003c/sub\u003e = D\u003csub\u003ek\u003c/sub\u003e(C\u003csub\u003ei\u003c/sub\u003e) ⊕ C\u003csub\u003ei-1\u003c/sub\u003e, and C\u003csub\u003e0\u003c/sub\u003e = IV\r\n\r\nIn CBC mode we also need a padding in the case the length of the plaintext doesn't fill all the block. For example we can have this plaintext and the following padding if the length of the block is 8 :\r\n\r\n`S|E|C|R|E|T| |M|E|S|S|A|G|E|02|02`\r\n\r\nYou can notice the length of SECRET MESSAGE is 14 so we need to fill two blocks of CBC equal 16. There are two bytes left, this is where the padding step in. You can see the two last byte 0202. Another example, if the padding had a length of 5, it will be fill with 05|05|05|05|05. Of course there is different way to fill the padding but in our case like most of the case the standard is [PKCS7](https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7) for the padding block.\r\n\r\nIf the padding does not match the PKCS7 standard it will produce an error. Example :\r\n\r\n`S|E|C|R|E|T| |M|E|S|S|A|G|E|03|03`\r\n\r\nWhen the block will be deciphered there will be a verification to check if the padding is good or not :\r\n\r\n`S|E|C|R|E|T| |M|E|S|S|A|G|E|03|03` =\u003e Wrong padding \u003cbr\u003e\r\n`S|E|C|R|E|T| |M|E|S|S|A|G|E|02|02` =\u003e Good padding\r\n\r\nNow imagine we can **know** when we have a bad padding and a good padding (the server send an \"error padding\" or \"404 not found\" when the padding is wrong etc). We will call this our [Oracle](http://security.stackexchange.com/questions/10617/what-is-a-cryptographic-oracle). The answers he will give us will be :\r\n\r\n* good padding\r\n* bad padding\r\n\r\nNow we know that, we can construct a block to retrieve one byte of the plaintext, don't forget this is a chosen-ciphertext attack.\r\nAn attacker will intercept a cipher text and retrieve byte by byte the plaintext.\r\n\r\n* intercepted cipher : C\u003csub\u003e0\u003c/sub\u003e | C\u003csub\u003e...\u003c/sub\u003e | C\u003csub\u003ei-1\u003c/sub\u003e | C\u003csub\u003ei\u003c/sub\u003e\r\n* then build a block like this :\r\n\r\nC'\u003csub\u003ei-1\u003c/sub\u003e = C\u003csub\u003ei-1\u003c/sub\u003e ⊕ 00000001 ⊕ 0000000X | C\u003csub\u003ei\u003c/sub\u003e\r\n\r\nWhere X is a char between `chr(0-256)`. \r\n\r\n* then he sends C'\u003csub\u003ei-1\u003c/sub\u003e \\| C\u003csub\u003ei\u003c/sub\u003e to the oracle. The oracle will decrypt like this :\r\n\r\nD\u003csub\u003ek\u003c/sub\u003e(C\u003csub\u003ei\u003c/sub\u003e) ⊕ C'\u003csub\u003ei-1\u003c/sub\u003e  \u003cbr\u003e\r\n= D\u003csub\u003ek\u003c/sub\u003e(C\u003csub\u003ei\u003c/sub\u003e) ⊕ C\u003csub\u003ei-1\u003c/sub\u003e ⊕ 00000001 ⊕ 0000000X \u003cbr\u003e\r\n= P\u003csub\u003ei\u003c/sub\u003e ⊕ 00000001 ⊕ 0000000X \u003cbr\u003e\r\n\r\nNow there is two possibilities: a padding error or not :\r\n\r\n* if we have a padding error :\r\n\r\n```\r\nIf P'i ⊕ 0000000Y == abcdefg5 then:\r\n    abcdefg0 ⊕ 00000001 = abcdefg5\r\n```\r\nThis is a wrong padding, so we can deduce the byte Y is wrong.\r\n\r\n* The oracle didn't give us a padding error and we know the byte X is good :\r\n\r\n```\r\nIf Pi ⊕ 0000000X == abcdefg0 then:\r\n    abcdefg0 ⊕ 00000001 = abcdefg1\r\n```\r\n\r\n\u003chr\u003e\r\n\r\n**For the second byte :**\r\n\r\n\r\nC'\u003csub\u003ei-1\u003c/sub\u003e = C\u003csub\u003ei-1\u003c/sub\u003e ⊕ 00000022 ⊕ 000000YX \\| C\u003csub\u003ei\u003c/sub\u003e\r\n\r\nAnd then : \r\n\r\nD\u003csub\u003ek\u003c/sub\u003e(C\u003csub\u003ei\u003c/sub\u003e) ⊕ C'\u003csub\u003ei-1\u003c/sub\u003e \u003cbr\u003e\r\n= D\u003csub\u003ek\u003c/sub\u003e(C\u003csub\u003ei\u003c/sub\u003e) ⊕ C\u003csub\u003ei-1\u003c/sub\u003e ⊕ 00000022 ⊕ 000000YX \u003cbr\u003e\r\n= P\u003csub\u003ei\u003c/sub\u003e ⊕ 00000001 ⊕ 00000YX \u003cbr\u003e\r\n\r\n* The oracle didn't give us a padding error and we know the byte X is good :\r\n\r\n```\r\nIf Pi ⊕ 000000YX == abcdef00 then:\r\n    abcdef00 ⊕ 00000022 = abcdef22\r\n```\r\n\r\netc etc for all the block. You can now launch the python script by reading the next section :)\r\n\r\n\r\n### Protection \r\n\r\n* Encrypt and MAC your data : http://security.stackexchange.com/questions/38942/how-to-protect-against-padding-oracle-attacks\r\n* Don't give error message like \"Padding error\", \"MAC error\", \"decryption failed\" etc\r\n\r\n## Options\r\n\r\nThe test file if you don't have target :\r\n\r\n```bash\r\npython test.py -m mysecretmessage\r\n```\r\n\r\nThe exploit : \r\n```\r\nusage: exploit.py [-h] -c CIPHER -l LENGTH_BLOCK_CIPHER --host HOST -u\r\n                  URLTARGET --error ERROR [--cookie COOKIE]\r\n                  [--method METHOD] [--post POST] [-v]\r\n```\r\nDetails required options:\r\n```bash\r\n-h help\r\n-c cipher chain\r\n-l length of a block example: 8 or 16\r\n-u UrlTarget for example: ?/page=\r\n--host hostname example: google.fr\r\n--error Error that the oracle gives you for a wrong padding\r\n    example: with HTTP method: 200,400,500\r\n             with DOM HTML   : \"\u003ch2\u003ePadding Error\u003c/h2\u003e\"\r\n```\r\nOptional options:\r\n```bash\r\n--cookie Cookie parameter example: PHPSESSID=9nnvje7p90b507shfmb94d7\r\n--method Default GET method but can set POST etc\r\n--post POST parameter if you need example 'user':'value', 'pass':'value'\r\n```\r\n\r\nExample:\r\n```bash\r\npython exploit.py -c E3B3D1120F999F4CEF945BA8B9326D7C3C8A8B02178E59AF506666542AB5EF44 -l 16 --host host.com -u /index.aspx?c= -v --error \"Padding Error\"\r\n```\r\n\r\n\u003ca href=\"https://asciinema.org/a/40222\" target=\"_blank\"\u003e\u003cimg src=\"https://asciinema.org/a/40222.png\" height=\"350\" width=\"550\" \u003e\u003c/a\u003e\r\n\r\n## Customisation\r\n\r\n\u003e I wan to customize the Oracle !\r\n\r\nExample with sockets https://gist.github.com/mpgn/fce3c3f2aaa2eeb8fac5\r\n\r\nNo problem, find these line and do what you have to do :)\r\n\r\n* Custom oracle response: \r\n```python\r\n#######################################\r\n# CUSTOMIZE YOUR RESPONSE ORACLE HERE #\r\n#######################################\r\n''' The function you want change to adapt the result to your problem '''\r\ndef test_validity(response,error):\r\n    try:\r\n        value = int(error)\r\n        if int(response.status) == value:\r\n            return 1\r\n    except ValueError:\r\n        pass  # it was a string, not an int.\r\n\r\n    # oracle repsonse with data in the DOM\r\n    data = response.read()\r\n    if data.find(error) == -1:\r\n        return 1\r\n    return 0\r\n```\r\n\r\n* Custom oracle call (HTTP)\r\n```python\r\n###################################\r\n# CUSTOMIZE YOUR ORACLE HTTP HERE #\r\n###################################\r\ndef call_oracle(host,cookie,url,post,method,up_cipher):\r\n    if post:\r\n        params = urllib.urlencode({post})\r\n    else:\r\n        params = urllib.urlencode({})\r\n    headers = {\"Content-type\": \"application/x-www-form-urlencoded\",\"Accept\": \"text/plain\", 'Cookie': cookie}\r\n    conn = httplib.HTTPConnection(host)\r\n    conn.request(method, url + up_cipher, params, headers)\r\n    response = conn.getresponse()\r\n    return conn, response\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpgn%2Fpadding-oracle-attack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpgn%2Fpadding-oracle-attack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpgn%2Fpadding-oracle-attack/lists"}